零、文章目录
微信小程序03-页面交互
1、案例:比较数字大小
(1)案例分析
- 需求:本案例将实现“比较数字大小”微信小程序,它的功能是当用户输入两个数字后,点击“比较”按钮可以自动比较这两个数字的大小。
- 两个输入框,可以输入数字,输入后点击“比较”按钮,按钮下方会显示比较结果。
- 比较结果有3种情况- 如果第1个数字比第2个数字大,则比较结果为“第1个数大”;- 如果第2个数字比第1个数字大,则比较结果为“第2个数大”;- 如果第1个数字和第2个数字相等,则比较结果为“两数相等”。
(2)知识储备-Page()函数
- 在微信小程序中,页面交互的代码写在页面的JS文件中,每个页面都需要通过Page()函数进行注册。需要注意的是,Page()函数只能写在微信小程序每个页面对应的JS文件中,并且每个页面只能注册一个。
- Page()函数的参数是一个对象,通过该对象可以指定页面初始数据、页面生命周期回调函数和页面事件处理函数。 - data:页面初始数据- onLoad:页面生命周期回调函数- onPullDownRefresh:页面事件处理函数
Page({// 页面初始数据data:{},// 页面生命周期回调函数,以onLoad()为例onLoad:function(){
console.log('onLoad()函数执行了')},// 页面事件处理函数,以onPullDownRefresh()为例onPullDownRefresh:function(){
console.log('onPullDownRefresh()函数执行了')}})
- 页面初始数据:页面初始数据是指页面第一次渲染时所用到的数据。
data:{msg1:'Hello',msg2:'World'},
- 页面生命周期回调函数:在微信小程序中,页面的生命周期是指每个页面“加载→渲染→销毁”的过程,每个页面都有生命周期。如果想要在某个特定的时机进行特定的处理,则可以通过页面生命周期回调函数来完成。
- 页面事件处理函数:在微信小程序中,用户可能会在页面上进行一些操作,例如上拉、下拉、滚动页面等,这些可以通过页面事件处理函数来完成。 - 使用onPullDownRefresh()函数前,需要在app.json配置文件中将enablePullDownRefresh配置项设为true。
(2)知识储备-数据绑定
- 数据绑定概念- 在微信小程序开发过程中,一般会将页面中的数据从WXML文件中分离出来,通过JS文件操作页面中的数据。- 假如有一个电商类的微信小程序,每个商品的详情页面的结构是相同的,区别是页面展示的数据不同。在实际开发中,开发者只编写一个页面,通过更改页面中的数据来实现不同的商品详情页面。这种开发方式是将页面中的数据分离出来,放到页面的JS文件中,通过程序控制页面中数据的展示。
- 数据绑定实现:微信小程序提供了Mustache语法(又称为双大括号语法)用于实现数据绑定,可将data中的数据通过Mustache语法输出到页面上。
- 数据绑定代码案例- 在pages/index/index.js文件中,在data中定义一个message数据-
Page({data:{message:'Hello World'}})
- 在pages/index/index.wxml文件中编写页面结构-<view>{{ message }}</view>
- 运行结果:页面上显示了message变量对应的值,也就是把“HelloWorld”渲染到页面代码中{{ message }}所在的位置,实现了从逻辑层到视图层的数据显示。
(2)知识储备-事件绑定
- 事件绑定:事件是视图层到逻辑层的通信方式,通过给组件绑定事件,可以监听用户的操作行为,然后在对应的事件处理函数中进行相应的业务处理。例如,为页面中的按钮绑定事件,当用户点击按钮时,就触发了事件。
- 常见的事件如下,分为两类- 冒泡事件:当一个组件上的事件被触发后,该事件会向父组件传递,比如点击事件、长按事件、触摸事件。- 非冒泡事件:当一个组件上的事件被触发后,该事件不会向父组件传递,比如其他事件。
- 事件绑定实现- 可以通过为组件添加“bind+事件名称”属性或“catch+事件名称”属性来完成,属性的值为事件处理函数,当组件的事件被触发时,会主动执行事件处理函数。- bind和catch的区别在于,bind不会阻止冒泡事件向上冒泡,而catch可以阻止冒泡事件向上冒泡。- 为组件绑定事件后,可以将事件处理函数定义在Page({})中。
- 事件绑定代码案例- 在pages/index/index.wxml文件中为button组件绑定tap事件-
<buttonbindtap="compare">比较</button>
- 在pages/index/index.js文件的Page({})中定义compare()函数-compare:function(){ console.log('比较按钮被单击了')},//可以写成简写形式compare(){ console.log('比较按钮被单击了')},
- 运行结果:单击“比较”按钮,在控制台输出“比较按钮被单击了”。
(2)知识储备-事件对象
- 事件对象- 在微信小程序的开发过程中,有时需要获取事件发生时的一些信息,例如事件类型、事件发生的时间、触发事件的对象等,此时可以通过事件对象来获取。- 当事件处理函数被调用时,微信小程序会将事件对象以参数的形式传给事件处理函数。
- 事件对象的属性如下- target:获取触发事件的组件的一些属性值集合。- currentTarget:获取当前组件的一些属性值集合。
- 事件对象代码案例- 修改pages/index/index.js文件中的compare()函数,通过参数接收事件对象,并将事件对象输出到控制台-
compare:function(e){ console.log(e)},
- 运行结果:单击“比较”按钮,控制台输出参数e表示事件对象。 - 事件对象代码案例-演示target和currentTarget区别- 在pages/index/index.wxml文件中编写页面结构-
<viewbindtap="viewtap"id="outer"> outer <viewid="inner"> inner </view></view>
- 在pages/index/index.js文件中添加viewtap()事件处理函数-viewtap:function(e){ console.log(e.target.id +'-'+ e.currentTarget.id)},
- 运行结果:当单击outer时,控制台中的输出结果为outer-outer,而单击inner时,控制台中的输出结果为inner-outer。由此可见,e.target获取的是子元素的属性值集合,而e.currentTarget获取的是父元素的属性值集合。
(2)知识储备-this关键字
- this关键字:在微信小程序开发过程中,有时需要在函数中访问页面中定义的一些数据,或者调用页面中定义的一些函数,此时可以通过this关键字来实现。this关键字代表当前页面对象。
- 代码演示:在onLoad()函数中通过this关键字访问data中的num数据并调用test()函数。程序运行后,在控制台中可以看到程序输出了this.data.num的值“1”和“test()函数执行了”。
Page({data:{num:1},// 定义data数据test:function(){// 定义test()函数
console.log('test()函数执行了')},onLoad:function(){
console.log(this.data.num)// 通过this关键字访问data中的num数据this.test()// 通过this关键字调用test()函数}})
(2)知识储备-setData()方法
- setData()方法- 通过数据绑定可以将data中定义的数据渲染到页面,但是如果数据发生了变化,页面并不会同步更新数据。- 为了实现在数据变化时使页面同步更新,微信小程序提供了setData()方法,该方法可以立即改变data中的数据,并通过异步的方式将数据渲染到页面上。
- setData()语法
this.setData(data[, callback])
- setData()代码案例- 在pages/index/index.js文件中编写页面中所需的数据message和事件处理函数changeText()-
Page({data:{message:'Hello World'},changeText:function(){this.setData({message:'hello微信小程序'})}})
- 在pages/index/index.wxml文件中编写页面结构-<viewbindtap="changeText">{{ message }}</view>
- 运行结果:单击前页面中显示的文字为“Hello World”,单击后页面中显示的文字为“hello微信小程序”。
(2)知识储备-条件渲染
- 条件渲染- 在微信小程序开发过程中,如果需要根据不同的判断结果显示不同的组件,可以使用条件渲染来实现。- 条件渲染通过标签的wx:if控制属性来完成。使用wx:if="{{ val }}"来判断是否需要渲染标签对应的组件,如果变量val的值为true,则渲染组件并输出;变量val的值为false,则不渲染组件。
- 代码演示:通过变量condition的值来控制是否渲染view组件。
<viewwx:if="{{ condition }}">True</view>
- 代码演示:- 给标签设置了wx:if控制属性后,可以为后面的标签设置wx:elif、wx:else控制属性。- wx:elif控制属性表示当前面标签的if条件不满足时,继续判断elif(else if)的条件;- wx:else控制属性表示当前面的if条件不满足时,渲染else对应的组件。- wx:else控制属性也可以直接出现在wx:if控制属性的后面。
<viewwx:if="{{ count < 1 }}">0</view><viewwx:elif="{{ count == 1 }}">1</view><viewwx:else>2</view>
(2)知识储备-
<block>
标签
<block>
标签:当使用一个判断条件决定是否显示或者隐藏多个组件时,通常会在其外部包裹一个<block>
标签,这样可直接控制这个外部标签的显示或隐藏。该标签并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,比view能耗低。
<blockwx:if="{{ true }}"><view>view1</view><view>view2</view></block>
(2)知识储备-hidden属性
- hidden属性 - 除wx:if控制属性外,hidden属性也可以控制组件的显示与隐藏,条件为true时隐藏组件里面的内容,条件为false时显示组件里面的内容- hidden属性和wx:if控制属性不同之处 - wx:if控制属性的初始渲染条件为false,只有条件第一次变为true的时候才开始渲染。- hidden属性所在的组件始终会被渲染,只是简单的控制显示与隐藏。
<texthidden="{{ hidden }}">hidden为true时不显示</text>
(3)案例实现
- 准备工作- ①创建项目。在微信开发者工具中创建一个新的微信小程序项目,项目名称为“比较数字大小”,模板选择“不使用模板”。- ②配置导航栏。在pages/index/index.json文件中配置页面导航栏。- ③配置样式。在pages/index/index.wxss文件中配置本项目的页面样式。
- 实现页面结构:在pages/index/index.wxml文件中编写“比较数字大小”微信小程序的页面结构。
<!--index.wxml--><view><text>请输入第1个数字:</text><inputtype="number"bindinput="num1Input"/></view><view><text>请输入第2个数字:</text><inputtype="number"bindinput="num2Input"/></view><buttonbindtap="compare">比较</button><view><textwx:if="{{ result }}">比较结果:{{ result }}</text></view>
- 实现事件处理函数:在pages/index/index.js文件的Page({})中编写事件处理函数
// index.jsPage({data:{result:''},num1:0,// 保存第1个数字num2:0,// 保存第2个数字num1Input:function(e){this.num1 =Number(e.detail.value)},num2Input:function(e){this.num2 =Number(e.detail.value)},compare:function(){var str =''if(this.num1 >this.num2){
str ='第1个数大'}elseif(this.num1 <this.num2){
str ='第2个数大'}else{
str ='两数相等'}this.setData({result: str
})}})
- 页面实现效果
2、案例:计算器
(1)案例分析
- 需求:在日常生活中,计算器是人们广泛使用的工具,可以帮助我们快速且方便地计算金额、成本、利润等。
- 在计算器中可以进行整数和小数的加(+)、减(-)、乘(×)、除(÷)运算。 - “C”按钮为清除按钮,表示将输入的数字全部清空;- “DEL”按钮为删除按钮,表示删除前面输入的一个数字;- “+/-”按钮为正负号切换按钮,用于实现正负数切换;- “.”按钮为小数点按钮,表示在计算过程中可以输入小数进行计算;- “=”按钮为等号按钮,表示对输入的数字进行计算。
(2)知识储备-data-*自定义属性
- 自定义属性- 在组件中,有时需要为事件处理函数传递参数。在Vue.js中可以直接使用函数进行传参,但是这种写法在微信小程序中并不适用。微信小程序可以通过自定义属性来进行传参。- 微信小程序中的
data-*
是一个自定义属性,data-*
自定义属性实际上是由data-前缀加上一个自定义的属性名组成的,属性名中如果有多个单词,用连字符“-”连接。-data-*
自定义属性的属性值表示要传参的数据。在事件处理函数中通过target或currentTarget对象的dataset属性可以获取数据。dataset属性是一个对象,该对象的属性与data-*
自定义属性相对应。需要注意的是,自定义属性名的连字符写法会被转换成驼峰写法,并且大写字母会自动转换成小写字母,例如,data-element-type会被转换为dataset对象的elementType属性,data-elementType会被转换为dataset对象的elementtype属性。 - 自定义属性代码实现- 在pages/index/index.wxml文件中编写页面结构-
<viewbindtap="demo"data-name="xiaochengxu"data-age="6">获取姓名和年龄</view><view>姓名:{{ name }}</view><view>年龄:{{ age }}</view>
- 在pages/index/index.js文件中编写页面逻辑-Page({data:{name:'初始名字',age:0},demo:function(e){this.setData({name: e.target.dataset.name,age: e.target.dataset.age })}})
- 运行结果:单击“获取姓名和年龄”,name编程xiaochengxu,age变成6
(2)知识储备-模块
- 模块:在微信小程序中,为了提高代码的可复用性,通常会将一些公共的代码抽离成单独的JS文件,作为模块使用,每个JS文件均为一个模块。
- 模块语法:微信小程序提供了模块化开发的语法,可以使用module.exports语法对外暴露接口,然后在需要使用模块的地方通过require()函数引入模块。
- 创建模块:在项目的根目录下创建一个utils目录,用于保存项目中的模块,然后在该目录下创建welcome.js文件
module.exports ={message:'welcome'}
- 引入模块:在页面的JS文件中使用require()函数将模块引入
var welcome =require('../../utils/welcome.js')Page({onLoad:function(){
console.log(welcome.message)}})
(3)案例实现
- 准备工作- ①创建项目。在微信开发者工具中创建一个新的微信小程序项目,项目名称为“计算器”,模板选择“不使用模板”。- ②配置导航栏。在pages/index/index.json文件中配置页面导航栏。- ③配置样式。在pages/index/index.wxss文件中配置本项目的页面样式。- ④创建utils文件夹。utils文件夹保存了项目中用到的两个公共文件,分别是math.js和calc.js。- math.js文件实现了数字的精确计算,用于解决JavaScript浮点型数据计算精度不准确的问题;-
// 精准计算功能,用于解决JavaScript浮点数运算精度不准确的问题module.exports ={add:function(arg1, arg2){var r1, r2, m try{ r1 = arg1.toString().split('.')[1].length }catch(e){ r1 =0}try{ r2 = arg2.toString().split('.')[1].length }catch(e){ r2 =0} m = Math.pow(10, Math.max(r1, r2))return(arg1 * m + arg2 * m)/ m },sub:function(arg1, arg2){var r1, r2, m, n try{ r1 = arg1.toString().split('.')[1].length }catch(e){ r1 =0}try{ r2 = arg2.toString().split('.')[1].length }catch(e){ r2 =0} m = Math.pow(10, Math.max(r1, r2))// 动态控制精度长度 n =(r1 >= r2)? r1 : r2 return((arg1 * m - arg2 * m)/ m).toFixed(n)},mul:function(arg1, arg2){var m =0, s1 = arg1.toString(), s2 = arg2.toString()try{ m += s1.split('.')[1].length }catch(e){}try{ m += s2.split('.')[1].length }catch(e){}returnNumber(s1.replace('.',''))*Number(s2.replace('.',''))/ Math.pow(10, m)},div:function(arg1, arg2){var t1 =0, t2 =0, r1, r2 try{ t1 = arg1.toString().split('.')[1].length }catch(e){}try{ t2 = arg2.toString().split('.')[1].length }catch(e){} r1 =Number(arg1.toString().replace('.','')) r2 =Number(arg2.toString().replace('.',''))return(r1 / r2)* Math.pow(10, t2 - t1)}}
- calc.js文件提供了一个计算器对象,用于简化开发逻辑。-const math =require('./math.js')// 计算器中的数字处理module.exports ={target:'num1',// 表示当前正在输入哪个数字num1:'0',// 保存第1个数字num2:'0',// 保存第2个数字op:'',// 运算符,值可以是 + - × ÷// 设置当前数字setNum(num){this[this.target]= num },// 获取当前数字getNum(){returnthis[this.target]},// 切换到第2个数字changeNum2(){this.target ='num2'},// 重置reset(){this.num1 =this.num2 ='0'this.target ='num1'this.op =''},// 进行计算getResult(){if(this.op ==='+'){return math.add(this.num1,this.num2)+''}elseif(this.op ==='-'){return math.sub(this.num1,this.num2)+''}elseif(this.op ==='×'){return math.mul(this.num1,this.num2)+''}elseif(this.op ==='÷'){return math.div(this.num1,this.num2)+''}}}
- 实现页面结构:在pages/index/index.wxml文件中编写“计算器”微信小程序的页面结构
<!--index.wxml--><viewclass="result"><!-- 结果区域 --><viewclass="result-sub">{{ sub }}</view><viewclass="result-num">{{ num }}</view></view><viewclass="btns"><!-- 按钮区域 --><!-- 按钮区域第1行按钮的结构 --><view><viewhover-class="bg"hover-stay-time="50"bindtap="resetBtn">C</view><viewhover-class="bg"hover-stay-time="50"bindtap="delBtn">DEL</view><viewhover-class="bg"hover-stay-time="50"bindtap="negBtn">+/-</view><viewhover-class="bg"hover-stay-time="50"bindtap="opBtn"data-val="÷">÷</view></view><!-- 按钮区域第2行按钮的结构 --><view><viewhover-class="bg"hover-stay-time="50"bindtap="numBtn"data-val="7">7</view><viewhover-class="bg"hover-stay-time="50"bindtap="numBtn"data-val="8">8</view><viewhover-class="bg"hover-stay-time="50"bindtap="numBtn"data-val="9">9</view><viewhover-class="bg"hover-stay-time="50"bindtap="opBtn"data-val="×">×</view></view><!-- 按钮区域第3行按钮的结构 --><view><viewhover-class="bg"hover-stay-time="50"bindtap="numBtn"data-val="4">4</view><viewhover-class="bg"hover-stay-time="50"bindtap="numBtn"data-val="5">5</view><viewhover-class="bg"hover-stay-time="50"bindtap="numBtn"data-val="6">6</view><viewhover-class="bg"hover-stay-time="50"bindtap="opBtn"data-val="-">-</view></view><!-- 按钮区域第4行按钮的结构 --><view><viewhover-class="bg"hover-stay-time="50"bindtap="numBtn"data-val="1">1</view><viewhover-class="bg"hover-stay-time="50"bindtap="numBtn"data-val="2">2</view><viewhover-class="bg"hover-stay-time="50"bindtap="numBtn"data-val="3">3</view><viewhover-class="bg"hover-stay-time="50"bindtap="opBtn"data-val="+">+</view></view><!-- 按钮区域第5行按钮的结构 --><view><viewhover-class="bg"hover-stay-time="50"bindtap="numBtn"data-val="0">0</view><viewhover-class="bg"hover-stay-time="50"bindtap="dotBtn">.</view><viewhover-class="bg"hover-stay-time="50"bindtap="execBtn">=</view></view></view>
- 实现页面逻辑:在pages/index/index.js文件的Page({})中编写页面逻辑
// index.jsconst calc =require('../../utils/calc.js')Page({data:{sub:'',num:'0'},// 设置3个变量标识numChangeFlag:false,execFlag:false,resultFlag:false,numBtn:function(e){// 点击数字按钮,获取对应的数字,将其值赋给numvar num = e.target.dataset.val
if(this.resultFlag){this.resetBtn()}if(this.numChangeFlag){this.numChangeFlag =falsethis.execFlag =true// 代表已输入第2个数字this.data.num ='0'// 将num设为0,避免数字进行拼接
calc.changeNum2()// 将target切换到第2个数字}// 设置输入的数字
calc.setNum(this.data.num ==='0'? num :this.data.num + num)// 在页面中显示输入的数字this.setData({num: calc.getNum()})},opBtn:function(e){
calc.op = e.target.dataset.val
this.numChangeFlag =true// 判断是否已经输入第2个数字if(this.execFlag){this.execFlag =false// 已经输入第2个数字,再判断当前是否为计算结果状态if(this.resultFlag){// 当前是计算结果状态,需要在计算结果的基础上计算this.resultFlag =false}else{// 连续计算,将计算结果作为第1个数字
calc.num1 = calc.getResult()}}this.setData({sub: calc.num1 +' '+ calc.op +' ',num: calc.num1
})},// “=”按钮的事件处理函数execBtn:function(){if(this.numChangeFlag){this.numChangeFlag =falsethis.execFlag =true
calc.num2 =this.data.num
}// 如果已经输入第2个数字,执行计算操作if(this.execFlag){this.resultFlag =truevar result = calc.getResult()this.setData({sub: calc.num1 +' '+ calc.op +' '+ calc.num2 +' = ',num: result
})
calc.num1 = result
}},resetBtn:function(){
calc.reset()// 调用reset()实现数字、运算符的重置this.execFlag =falsethis.numChangeFlag =falsethis.resultFlag =falsethis.setData({sub:'',num:'0'})},// “.”按钮(小数点按钮)的事件处理函数dotBtn:function(){// 如果当前是计算结果状态,则重置计算器if(this.resultFlag){this.resetBtn()}// 如果等待输入第2个数字且还没有输入第2个数字,设为“0.”if(this.numChangeFlag){this.numChangeFlag =false
calc.setNum('0.')}elseif(this.data.num.indexOf('.')<0){// 如果当前数字中没有“.”,需要加上“.”
calc.setNum(this.data.num +'.')}this.setData({num: calc.getNum()})},// DEL按钮(删除按钮)的事件处理函数delBtn:function(){// 如果当前是计算结果状态,则重置计算器if(this.resultFlag){returnthis.resetBtn()}// 非计算结果状态,删除当前数字中最右边的一个字符var num =this.data.num.substr(0,this.data.num.length -1)
calc.setNum(num ===''|| num ==='-'|| num ==='-0.'?'0': num)this.setData({num: calc.getNum()})},// “+/-”按钮(正负切换按钮)的事件处理函数negBtn:function(){// 如果是0,不加正负号if(this.data.num ==='0'||this.data.num ==='0.'){return}// 如果当前是计算结果状态,则重置计算器if(this.resultFlag){this.resetBtn()}elseif(this.data.num.indexOf('-')<0){// 当前没有负号,加负号
calc.setNum('-'+this.data.num)}else{// 当前有负号,去掉负号
calc.setNum(this.data.num.substr(1))}this.setData({num: calc.getNum()})}})
- 页面实现效果
3、案例:美食列表
(1)案例分析
- 需求:“美食列表”微信小程序是一个展示美食名称、美食图片及美食商家的电话、地址和营业时间等信息的微信小程序。
- 美食列表包含多条美食信息 - 每条美食信息左侧为美食图片- 右侧为美食详细信息,包括美食名称、电话、地址和营业时间。
- 该页面具有上拉触底加载数据和下拉刷新两个功能 - 用户上拉美食列表页时,如果页面即将到达底部,会自动加载更多数据;- 用户下拉页面时,如果到达顶部后进行下拉操作,可以刷新页面。
(2)知识储备-列表渲染
- 列表渲染- 为了方便用户查找美食信息,微信小程序的页面通常以列表的形式展示美食信息。- 在实际开发中,通常将列表数据保存为数组或对象,然后在页面中通过列表渲染的方式输出数据。
- 列表渲染语法- 列表渲染通过wx:for控制属性来实现。微信小程序进行列表渲染时,会根据列表中数据的数量渲染相应数量的内容。- 在wx:for控制属性所在标签的内部 - 使用item变量获取当前项的值- 使用index变量获取当前项的数组索引或对象属性名。- 如果不想使用item和index这两个变量名,还可以通过wx:for-item控制属性更改item的变量名;通过wx:for-index控制属性更改index的变量名。- wx:for控制属性通常搭配wx:key控制属性使用 - wx:key控制属性用于为每一项设置唯一标识,这样可以在数据改变后页面重新渲染时,使原有组件保持自身的状态。- 在设置wx:key的值时,如果item本身就是一个具有唯一性的字符串或数字,则可以将wx:key的值设置为
*this
,*this
表示item本身。 - 代码案例演示- 在pages/index/index.js文件的Page({})中编写页面数据-
data:{arr:['a','b','c']}
- 在pages/index/index.wxml文件中编写页面结构,通过列表渲染的方式将arr数组渲染到页面中-<viewwx:for="{{ arr }}"wx:key="*this"> {{ index }} {{ item }}</view>
- 代码案例演示:对象数组- 在pages/index/index.js文件的Page({})中编写页面数据-
data:{list:[{message:'梅',id:1},{message:'兰',id:2},{message:'竹',id:3},{message:'菊',id:4}]}
- 在pages/index/index.wxml文件中编写页面结构,将list数组中的数据在页面中显示出来-<viewwx:for="{{ list }}"wx:key="id">{{ index }}-----{{ item.message }}======={{ item.id }}</view>
- 代码案例演示:通过wx:for-item、wx:for-index更改item和index的变量名-
<viewwx:for="{{ list }}"wx:for-item="item2"wx:for-index="index2"wx:key="id">{{ index2 }}:{{ item2.message }}</view>
(2)知识储备-网络请求
- 网络请求- 客户端与服务器进行交互时,客户端请求服务器的过程称为网络请求。- 例如,获取用户的头像信息,需要客户端向服务器发送请求,服务器查询到数据后把数据传递给客户端。- 在微信小程序中实现网络请求时,需要服务器给微信小程序提供服务器接口。
- 微信对接口的安全限制- ①只能请求HTTPS协议的服务器接口。- ②必须登录微信小程序管理后台,将服务器接口的域名添加到信任列表中。- 当服务器接口不满足以上两个条件时,可以在微信开发者工具的本地设置中勾选“不校验合法域名、web-view(业务域名)、TLS版本以及HTTPS证书”复选框,跳过对服务器接口的校验。但是此做法仅限在开发与调试阶段使用。
- 网络请求语法- 在微信小程序中发起网络请求可以通过调用wx.request()方法来实现。- wx.request()方法的常见选项如下 - method选项的合法值包括OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE和CONNECT
- 网络请求代码演示- 每个wx.request()方法都是一个请求任务,可以通过abort()方法将其取消-
// 发起网络请求var requestTask = wx.request({url:'URL地址',// wx.request()的常见参数……})// 取消请求任务 requestTask.abort()
- 通过wx.request()方法发起一个GET方式的请求-wx.request({url:'URL地址',method:'GET',data:{name:'zs'},success:res=>{ console.log(res)}})
(2)知识储备-提示框
- wx.showLoading()方法- wx.showLoading()方法用于弹出加载提示框,加载提示框弹出后,不会自动关闭,需要手动调用wx.hideLoading()方法才能关闭载提示框。- wx.showLoading()方法的常用选项如下- 代码演示如下
wx.showLoading({title:'加载中',})setTimeout(function(){ wx.hideLoading()},2000)
- wx.showToast()方法- wx.showToast()方法用于显示消息提示框,该方法的常用选项如下 - icon选项的合法值包括success(成功图标)、error(失败图标)、loading(加载图标)和none(无图标)。 - 当icon的值为success、error、loading时,title选项中文本最多显示7个汉字长度;- 当icon的值为none时,title选项中文本最多可显示两行。- 代码演示如下
wx.showToast({title:'成功',icon:'success',duration:2000})
(2)知识储备-WXS
- WXS- WXS(WeiXin Script)是微信小程序独有的一套脚本语言,可以结合WXML构建出页面结构。- WXS的典型应用场景是“过滤器”,所谓的过滤器是指在渲染数据之前,对数据进行处理,处理结果最终会显示在页面上。
- WXS的4个特点- WXS与JavaScript不同 - ①WXS有8种数据类型,包括number(数值)、string(字符串)、boolean(布尔)、object(对象)、function(函数)、array(数组)、date(日期)、regexp(正则)。- ②WXS不支持let、const、解构赋值、展开运算符、箭头函数、对象属性简写等语法,WXS支持var定义变量、普通function函数等语法。- ③WXS遵循CommonJS规范。在每个模块内部,module变量代表当前模块,这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。在使用require()函数引用其他模块时,得到的是被引用模块中module.exports所指的对象。- WXS不能作为组件的事件回调:WXS经常与Mustache语法配合使用,但是在WXS中定义的函数不能作为组件的事件回调函数。- 具有隔离性:隔离性是指WXS代码的运行环境和其他JavaScript代码是隔离的,体现在以下两个方面。 - ①在WXS代码中不能调用页面的JS文件定义的函数。- ②在WXS代码中不能调用微信小程序提供的API。- 在iOS设备上效率高:在iOS设备上,微信小程序内WXS代码的执行速度比JavaScript代码快2~20倍;在Android设备上,两者的运行效率无差异。
- WXS语法- WXS代码可以写在页面的WXML文件的
<wxs>
标签内(内嵌WXS脚本)。- WXS代码可以写在以.wxs为后缀名的文件中(外联WXS脚本)。- 每一个.wxs文件和<wxs>
标签均为一个单独的模块,有自己独立的作用域,即在一个模块内定义的变量和函数默认为私有的,对其他模块不可见。- 在页面的WXML文件中使用<wxs>
双标签语法时,必须提供module属性,用于指定当前WXS的模块名称,以便于在WXML中访问模块中的成员;当<wxs>
标签为单闭合标签或标签中内容为空时需提供src属性,src属性的属性值为引用的.wxs文件的相对路径。 - WXS代码演示-内嵌WXS脚本:在pages/index/index.wxml文件中编写页面结构并内嵌WXS脚本
<wxsmodule="m1">
function toUpper(str) {
return str.toUpperCase()
}
module.exports = {
toUpper: toUpper
}
</wxs><view>
{{ m1.toUpper('weixin') }}
</view>
- WXS代码演示-外联WXS脚本:- 通常情况下,将以.wxs为后缀名的文件存放在utils目录下,该目录用于存放工具类函数或公共模块。首先在utils/tool.wxs文件中编写外链WXS脚本。
var msg ='hello world' module.exports ={message: msg }
- 在pages/index/index.wxml文件中编写页面结构。<wxsmodule="m2"src="../../utils/tool.wxs"></wxs><view> {{ m2.message }} </view>
(2)知识储备-上拉触底
- 上拉触底- 在原生应用或者网页的交互中,经常会有上拉加载这个功能。用户在浏览列表页面时,手指在手机屏幕上进行上拉滑动操作,通过上拉加载请求数据,增加列表数据。- 微信小程序提供了onReachBottom()事件处理函数,即页面上拉触底事件处理函数,用于监听当前页面的上拉触底事件。- onReachBottom()事件处理函数的示例代码如下
onReachBottom:function(){ console.log('触发了上拉触底的事件')},
- 上拉触底默认距离- 在默认情况下,触发上拉触底事件时,滚动条距离页面底部的距离为50px,即上拉触底距离为50px。- 在实际开发中,开发人员可以根据实际需求,在全局或页面的JSON配置文件中,通过onReachBottomDistance属性修改上拉触底的距离。
(2)知识储备-下拉刷新
- 下拉刷新- 在原生应用的交互中,经常会有下拉刷新操作,即当用户下拉页面到达顶部时,再进行下拉可以将数据重新加载。- 在微信小程序中,也可以实现下拉刷新的效果。启用下拉刷新有2种方式。- 全局开启下拉刷新:在app.json文件的window节点中,将enablePullDownRefresh设置为true。- 局部开启下拉刷新:在页面的JSON文件中,将enablePullDownRefresh设置为true。- 开启下拉刷新后,当下拉操作执行时,就会触发onPullDownRefresh()事件处理函数。
onPullDownRefresh:function(){ console.log('触发了下拉刷新的事件')}
- 加载提示弹回时机设定- 当执行了下拉刷新操作后,页面顶部会出现加载提示,并且页面需要延迟一段时间才会弹回去。- 为了优化用户体验,可以在完成下拉刷新的数据加载后,立即调用wx.stopPullDownRefresh()方法停止使用当前页面的下拉刷新加载效果。
wx.stopPullDownRefresh()
(3)案例实现
- 准备工作- ①创建项目。在微信开发者工具中创建一个新的微信小程序项目,项目名称为“美食列表”,模板选择“不使用模板”。- ②配置页面。项目创建完成后,在app.json文件中配置一个shoplist页。
"pages":["pages/shoplist/shoplist"],
- ③配置导航栏。在pages/shoplist/shoplist.json文件中配置页面导航栏。- ④配置页面样式。在pages/shoplist/shoplist.wxss文件中配置页面样式。- ⑤启动服务器。切换工作目录到nodejs服务程序目录,打开命令提示符,然后在命令提示符中执行如下命令,启动服务器。node index.js
- 获取初始数据:在pages/shoplist/shoplist.js文件的Page({})中编写页面逻辑。
// pages/shoplist/shoplist.jsPage({data:{shopList:[],// 保存美食列表信息},listData:{page:1,// 默认请求第1页的数据pageSize:10,// 默认每页请求10条数据total:0// 数据总数,默认为0},isLoading:false,// 当前是否正在加载数据getShopList:function(cb){this.isLoading =true// 请求数据之前,展示加载效果,接口调用结束后,停止加载效果
wx.showLoading({title:'数据加载中...'})
wx.request({url:'http://127.0.0.1:3000/data',method:'GET',data:{page:this.listData.page,pageSize:this.listData.pageSize
},success:res=>{
console.log(res)this.setData({shopList:[...this.data.shopList,...res.data],})this.listData.total = res.header['X-Total-Count']-0},complete:()=>{// 隐藏加载效果
wx.hideLoading()this.isLoading =false
cb &&cb()}})},onLoad(){this.getShopList()},onReachBottom:function(){if(this.listData.page *this.listData.pageSize >=this.listData.total){// 没有下一页的数据了return wx.showToast({title:'数据加载完毕!',icon:'none'})}if(this.isLoading){return}// 页码自增++this.listData.page
// 请求下一页数据this.getShopList()},onPullDownRefresh:function(){// 需要重置的数据this.setData({shopList:[]})this.listData.page =1this.listData.total =0// 重新发起数据请求this.getShopList(()=>{
wx.stopPullDownRefresh()})}})
- 实现页面渲染:在pages/shoplist/shoplist.wxml文件中进行页面渲染。
<!--pages/shoplist/shoplist.wxml--><wxssrc="../../utils/tools.wxs"module="tools"></wxs><viewclass="shop-item"wx:for="{{ shopList }}"wx:key="id"><viewclass="thumb"><imagesrc="{{ item.image }}"></image></view><viewclass="info"><textclass="shop-title">{{ item.name }}</text><text>电话:{{ tools.splitPhone(item.phone) }}</text><text>地址:{{ item.address }}</text><text>营业时间:{{ item.businessHours }}</text></view></view>
- 处理电话格式:在项目根目录下创建utils文件夹,将处理电话函数封装到utils/tools.wxs文件中。
functionsplitPhone(str){if(str.length !==11){return str
}var arr = str.split('')
arr.splice(3,0,'-')
arr.splice(8,0,'-')return arr.join('')}
module.exports ={splitPhone: splitPhone
}
- 设置上拉触底距离和下拉刷新及样式:在pages/shoplist/shoplist.json文件中配置上拉触底的距离为200px。
{"navigationBarTitleText":"美食","onReachBottomDistance":200,"enablePullDownRefresh":true,"backgroundColor":"#efefef","backgroundTextStyle":"dark"}
- 页面实现效果
4、案例:问卷调查
(1)案例分析
- 需求:调查问卷又称调查表或询问表,是以问题的形式系统地记载调查内容的一种印件。传统的调查问卷是纸质的,发布和收集都不太方便,而通过微信小程序制作调查问卷,可以在短时间内快速收集反馈信息,相比纸质调查问卷极大地提高了效率。假设有一位大学老师,想通过调查问卷来了解同学们的专业技能、对开设公开课的意见等信息,从而根据同学们的建议制订下一步的教学计划。
- 调查问卷需要填写的信息包括姓名、性别、专业技能和您的意见。 - “姓名”通过单行输入框填写。- “性别”通过单选框选择。- “专业技能”通过多选框选择。- “您的意见”通过多行输入框填写。- 页面底部的“提交”按钮用于将用户输入的信息提交。
(2)知识储备-双向数据绑定
- 单向数据绑定- 普通属性的绑定都是单向的,如果使用this.setData({ value:‘leaf’ })来更新value,则this.data.value和输入框中显示的值都会被更新为leaf
<inputvalue="{{ value }}"/>
- 但是如果用户在页面中修改了输入框里的值,则this.data.value的值不会发生改变。 - 双向数据绑定:- 双向数据绑定的实现方式是在对应属性之前添加model:前缀。
<inputmodel:value="{{ value }}"/>
- 如果输入框的值被更改了,this.data.value也会随之更改。同时,页面的WXML文件中所有绑定了value的位置也会被一同更新,数据监听器也会被正常触发。
(3)案例实现
- 准备工作- ①创建项目。在微信开发者工具中创建一个新的微信小程序项目,项目名称为“调查问卷”,模板选择“不使用模板”。- ②配置页面。项目创建完成后,在app.json文件中配置1个form页面。
"pages":["pages/form/form"],
- ③配置导航栏。在pages/form/form.json文件中配置页面导航栏。- ④配置页面样式。在pages/form/form.wxss文件中配置页面样式。- ⑤启动服务器。切换工作目录到nodejs服务程序目录,打开命令提示符,然后在命令提示符中执行如下命令,启动服务器。node index.js
- 获取初始数据:在pages/form/form.js文件的onLoad()事件处理函数中实现页面加载完成时自动向服务器发送请求,获取表单中的初始数据。
// pages/form/form.jsPage({data:{},onLoad:function(){
wx.showLoading({title:'数据加载中'})
wx.request({url:'http://127.0.0.1:3000/',success:res=>{// statusCode为HTTP状态码,200表示网络请求成功,数据获取成功if(res.statusCode ===200){this.setData(res.data)
console.log(res.data)}else{
wx.showModal({title:'服务器异常'})}setTimeout(()=>{
wx.hideLoading()},500)},fail:function(){
wx.hideLoading()
wx.showModal({title:'网络异常,无法请求服务器'})},})},radioChange:function(e){var val = e.detail.value
this.data.gender.forEach((v)=>{
v.value === val ? v.checked =true: v.checked =false})},checkboxChange:function(e){var val = e.detail.value
this.data.skills.forEach((v)=>{
val.includes(v.value)? v.checked =true: v.checked =false})},submit:function(){
wx.request({url:'http://127.0.0.1:3000',method:'POST',data:this.data,success:res=>{
wx.showModal({title:'提交完成',showCancel:false})}})}})
- 实现页面渲染:在pages/form/form.wxml文件中编写内容区域的整体结构。
<!--pages/form/form.wxml--><viewclass="container"><!-- 姓名区域 --><view><text>姓名:</text><inputtype="text"model:value="{{ name }}"/></view><!-- 性别区域 --><view><text>性别:</text><radio-groupbindchange="radioChange"><labelwx:for="{{ gender }}"wx:key="value"><radiovalue="{{ item.value }}"checked="{{ item.checked }}"/>
{{ item.name }}
</label></radio-group></view><!-- 专业技能区域 --><view><text>专业技能:</text><checkbox-groupbindchange="checkboxChange"><labelwx:for="{{ skills }}"wx:key="value"><checkboxvalue="{{ item.value }}"checked="{{ item.checked }}"/>
{{ item.name }}
</label></checkbox-group></view><!-- 意见区域 --><view><text>您的意见:</text><textareamodel:value="{{ opinion }}"/></view><buttontype="primary"bindtap="submit">提交</button></view>
- 页面实现效果
本文转载自: https://blog.csdn.net/liyou123456789/article/details/142356838
版权归原作者 李宥小哥 所有, 如有侵权,请联系我们删除。
版权归原作者 李宥小哥 所有, 如有侵权,请联系我们删除。