第5章 莫凡商城的注册、登录功能
第5章莫凡商城的注册、登录功能
假设要开发一个社交平台的微信小程序,为了让用户能够注册和登录,可以设计一个表单来提供注册、登录功能。通过表单组件,用户
可以输入用户名和密码进行注册和登录操作。为了提升用户体验,可以使用界面交互API来添加动画效果和提示信息,让用户更加轻松地进
行操作。为了方便用户下次登录,可以使用缓存API将用户的登录状态保存在本地,实现自动登录的功能。这样,用户就能够方便快捷地使
用社交平台小程序,并享受到丰富的社交功能。
注册、登录功能是非常通用的功能,几乎所有的网站、App、小程序等都会用到注册、登录功能。莫凡商城的注册、登录等功能的设置会用
到微信小程序的表单组件,涉及微信小程序的界面交互API、数据缓存 API及登录相关API。在了解这些基础知识之后,就可以实现莫凡商城
的注册页面、登录页面、修改密码页面、意见反馈页面和清除缓存功能。

5.1微信小程序表单组件
微信小程序提供了丰富的表单组件,包括button组件、checkbox组件、radio组件、input组件、textarea组件、label组件、picker组件、
slider组件、switch组件、form组件。
5.1.1 按钮组件button
button组件提供了3种类型的按钮:基本类型按钮、默认类型按钮及警告类型按钮。按钮的大小有默认和迷你两种。图5.1展示了按钮的类型
和大小。

图5.1 按钮的类型和大小
button组件有很多属性,不同属性有不同的作用。button组件的属性如表5.1所示。
表5.1 button组件的属性属性类型默认值说明sizestringdefault按钮的大小,有效值为default、
minitypestringdefault按钮的样式类型,有效值为基本类型primary、默认类型default、警告类型
warnplainbooleanfalse指定按钮是否镂空、背景色透明disabledbooleanfalse指定是否禁用loadingbooleanfalse指
定名称前是否带loading图标form-typestring用于form组件。有效值为submit、reset,点击后分别会触发submit、
reset事件open-typestring微信开放能力,如下所示。open-typestringcontact:打开客服会话,如果用户在会话中
点击消息卡片后返回小程序,可以从bindcontact回调中获得具体信息。share:触发用户转发事件。
getPhoneNumber:获取用户手机号。可以从bindgetphonenumber回调中获取用户信息。getUserInfo:获取用户
信息。可以从bindgetuserinfo回调中获取用户信息。launchApp:打开App。可以通过app-parameter属性设定向
App传递参数。openSetting:打开授权设置页。feedback:打开“意见反馈”页面。用户可提交反馈内容并上传日
志;开发者可以登录小程序管理后台,进入“客服反馈”页面获取反馈内容hover-classstringbutton-hover指定按钮
按下时的样式类。当hover-class="none"时,没有点击态效果hover-stop-propagationbooleanfalse指定是否阻止
本节点的祖先节点出现点击态hover-start-timenumber20设置按住后多久出现点击态,单位为mshover-stay-
timenumber70设置手指松开后点击态保留的时间,单位为mslangstringen指定返回用户信息的语言,zh_CN为简
体中文,zh_TW为繁体中文,en为英文session-fromstring会话来源,open-type="contact"时有效send-message-
titlestring当前标题会话内消息卡片标题,open-type="contact"时有效send-message-pathstring当前分享路径会
话内消息卡片点击跳转小程序路径,open-type="contact"时有效send-message-imgstring图片会话内消息卡片图
片,open-type="contact"时有效app-parameterstring打开App时,向App传递的参数,open-type="launchApp"时
有效show-message-cardbooleanfalse指定是否显示会话内消息卡片。设置此参数为true,用户进入客服会话会在
右下角显示“可能要发送的小程序”提示,用户点击后可以快速发送小程序消息。open-type="contact"时有效
bindgetuserinfoeventhandle用户点击该按钮时,会返回获得的用户信息。回调的detail数据与wx.getUserInfo返回
的一致。open-type="getUserInfo"时有效bindcontacteventhandle客服消息回调,open-type="contact"时有效
bindgetphonenumbereventhandle获取用户手机号回调,open-type="getPhoneNumber"时有效
binderroreventhandle当使用微信开放能力发生错误时的回调,open-type="launchApp"时有效
bindopensettingeventhandle在打开授权设置页后的回调,open-type="openSetting"时有效
bindlaunchappeventhandle打开App成功的回调,open-type="launchApp"时有效bindchooseavatareventhandle获
取用户头像回调,open-type="chooseAvatar"时有效
从button组件的属性中可以看出,按钮可以设置不同大小、不同类型、是否镂空、是否禁用、按钮名称前是否带loading图标等。针对form组
件,button组件提供了提交表单和重置表单两个功能,示例代码如下:
<button type="default" size="{{defaultSize}}" loading="{{loading}}" plain="{{plain}}"
disabled="{{disabled}}" bindtap="default" style="margin:10px"> default </button>
<button type="primary" size="{{primarySize}}" loading="{{loading}}" plain="{{plain}}"
disabled="{{disabled}}" bindtap="primary" style="margin:10px"> primary</button>
<button type="warn" size="{{warnSize}}" loading="{{loading}}" plain="{{plain}}"
disabled="{{disabled}}" bindtap="warn" style="margin:10px"> warn </button>
<button bindtap="setDisabled" style="margin:10px">点击设置以上按钮的disabled属性 </button>
<button bindtap="setPlain" style="margin:10px">点击设置以上按钮的plain属性</button>
<button bindtap="setLoading" style="margin:10px">点击设置以上按钮的loading属性 </button>
var types = ['default', 'primary', 'warn']
var pageObject = {
data: {
defaultSize: 'default',
primarySize: 'default',
warnSize: 'default',
disabled: false,
plain: false,
loading: false
},
setDisabled: function(e) {
this.setData({
disabled: !this.data.disabled
})
},
setPlain: function(e) {
this.setData({
plain: !this.data.plain
})
},
setLoading: function(e) {
this.setData({
loading: !this.data.loading
})
}
}
for (var i = 0; i < types.length; ++i) {
(function(type) {
pageObject[type] = function(e) {
var key = type + 'Size'
var changedData = {}
changedData[key] =
this.data[key] === 'default' ? 'mini' : 'default'
this.setData(changedData)
}
})(types[i])
}
Page(pageObject)
运行上述代码,结果如图5.2所示。

图5.2 运行结果
5.1.2 多选项目组件checkbox
Checkbox组件是多选项目组件,也叫多项选择器,即常说的复选框,常用来进行多项选择,它的属性如表5.2所示。
表5.2 checkbox组件的属性属性类型默认值说明valuestring<checkbox/>标识,选中时触发
<checkbox-group/>的change事件,并携带<checkbox/>的valuedisabledbooleanfalse指定是否禁用
checkedbooleanfalse指定当前是否选中colorstringcheckbox的颜色,同CSS的color
checkbox-group是用来容纳多个checkbox组件的多项选择器容器,它有一个绑定事件bindchange,<checkbox-group/>中的选中项发生变
化时会触发bindchange事件,event.detail={value:[选中的checkbox的 value的数组]}。
下面演示checkbox组件的使用方法,以及获取选中的value的方法。
(1)在WXML文件里使用checkbox进行页面布局,示例代码如下:
<view style="text-align:center;margin:10px;">
<checkbox-group bindchange="checkboxChange">
<checkbox value="篮球" />篮球
<checkbox value="足球" checked="true" />足球
<checkbox value="排球" />排球
<checkbox value="橄榄球" disabled/>橄榄球
</checkbox-group>
</view>
(2)在JS文件里,添加checkboxChange()事件函数,获取选中复选框的值,并将其输出,示例代码如下:
Page({
checkboxChange:function(e){
console.log(e.detail.value)
}
})
多选项目组件的效果和value如图5.3所示。

图5.3 多选项目组件的效果和value
从图5.3中可以看出,被禁用的多选项目是不能使用的。此时绑定 bindchange事件,选中项改变时会将多选项目的value以数组的形式存
在detail里,通过e.detail.value就可以获得多选项目的value。
多选项目的样式是可以重新定义的,可以不使用默认的效果。下面演示自定义多选项目的样式,示例代码如下:
/*checkbox整体大小 */
checkbox {
width:200rpx;
height:80rpx;
}
/*checkbox复选框大小 */
checkbox.wx-checkbox-input{
width:50rpx;
height:50rpx;
}
/*checkbox选中后样式 */
checkbox.wx-checkbox-input.wx-checkbox-input-checked {
background:#f50410;
}
/*checkbox选中后图标样式 */
checkbox.wx-checkbox-input.wx-checkbox-input-checked::before {
width:28rpx;
height:28rpx;
line-height:28rpx;
text-align:center;
font-size:22rpx;
color:#fff;
background:transparent;
transform:translate(-50%, -50%) scale(1);
-webkit-transform: translate(-50%,-50%)scale(1);
}
自定义多选项目样式的效果如图5.4所示。

图5.4 自定义的多选项目样式的效果
5.1.3 单选项目组件radio
Radio组件是单选项目组件,也叫单项选择器,是很常用的表单组件,每次只能选中一个选项,选项间是互斥关系,如选择性别时,“男”和
“女”选项只能选其一,它的属性如表5.3所示。
表5.3 radio组件的属性属性类型默认值说明valuestring<radio/>标识。当该<radio/>被选中时,
<radio-group/>的change事件会携带<radio/>的valuedisabledbooleanfalse指定是否禁用checkedbooleanfalse指
定当前是否选中colorcolorradio的颜色,同CSS的color
radio-group是用来容纳多个radio组件的单项选择器容器,它有一个绑定事件bindchange,<radio-group/>中的选中项发生变化时会触发
bindchange事件,event.detail={value:选中的radio的value}。
下面演示radio组件的使用方法。
(1)在WXML文件里使用radio组件进行页面布局,示例代码如下:
<view style="text-align:center;margin:10px;">
<radio-group class="radio-group" bindchange="radioChange">
<radio value="男" />男
<radio value="女" checked/>女
<radio value="未知" disabled/>未知
</radio-group>
</view>
(2)在JS文件里添加radioChange()事件函数,获取选中单选项目的值,并将其输出,示例代码如下:
Page({
radioChange:function(e){
console.log('radio发生change事件,携带value为:',e.detail.value)
}
})
单选项目组件的效果和value如图5.5所示。

图5.5 单选项目组件的效果和value
从图5.5可以看出,被禁用的单选项目是不能选择的。在radio-group上绑定bindchange事件后,每次选择时,只能选择一个选项,同时会把
相应的value存在detail里。
5.1.4 输入框组件input
input组件是用来输入单行文本内容的输入框组件,它的属性如表5.4所示。
表5.4 input组件的属性属性类型默认值说明valuestringinput输入框的初始内容typestringtextinput输
入框的类型,有效值有text(文本输入键盘)、number(数字输入键盘)、idcard(身份证输入键盘)、digit(带小
数点的数字键盘)、safe- password(密码安全输入键盘)、nickname(昵称输入键盘)passwordbooleanfalse指
定是否为密码类型placeholderstringinput输入框为空时的占位符placeholder-stylestring指定placeholder的样式
placeholder-classstringinput-placeholder指定placeholder的样式类disabledbooleanfalse指定是否禁用
maxlengthnumber140最大输入长度,设置为−1的时候不限制长度cursor-spacingnumber0指定光标与键盘的距
离。取input输入框距离底部的距离和cursor-spacing指定的距离中的最小值auto-focusbooleanfalse指定是否自动
聚焦,唤起键盘focusbooleanfalse指定是否获取焦点confirm-typestringdone设置键盘右下角按钮的文字,仅在
type="text"时生效。send表示右下角按钮为“发送”,search表示右下角按钮为“搜索”,next表示右下角按钮为“下
一个”,go表示右下角按钮为“前往”,done表示右下角按钮为“完成”always-embedbooleanfalse强制input输入框处
于同层或非同层状态,默认focus时input输入框会切到非同层状态(仅在iOS下生效)confirm-holdbooleanfalse点
击键盘右下角按钮时是否保持键盘不收起cursornumber指定聚焦时的光标位置selection-startnumber−1光标起始
位置,自动聚焦时有效,需与
selection- end搭配使用selection-endnumber−1光标结束位置,自动聚焦时有效,需与selection-start搭配使用
bindconfirmeventhandle点击“完成”按钮时触发,event.detail={value: value}bindkeyboardheight-
changeeventhandle键盘高度发生变化的时候触发,event.detail=
{height: height,duration:duration}bindnicknamerevieweventhandle用户昵称审核完毕后触发,仅在
type="nickname"时有效,event.detail={pass,timeout}bindinputeventhandle用户使用键盘输入时,触发input事
件,event.detail ={value:value}。处理函数可以直接返回一个字符串,替换input输入框中的内容
bindfocuseventhandleinput输入框聚焦时触发,event.detail={value:value}bindblureventhandleinput输入框失去
焦点时触发,event.detail={value:value}
从表5.4中可以看出以下几点。
- 可以设置input输入框的类型,有text(文本输入键盘)、number(数
字输入键盘)、idcard(身份证输入键盘)、digit(带小数点的数字键盘)等,可根据不同的场景使用不同的输入类型。
- 可以设置input输入框是否为密码类型,如果是密码类型,则会用点
号代替具体值显示,这也是密码输入框的常用处理方式。
- 可以用placeholder来给input输入框添加提示信息,如“请输入手机号/
用户名/邮箱”,用placeholder-style设置提示信息的样式,用 placeholder-class设置提示信息的class,然后再针对这个class添加样
式。
- 可以设置input输入框是否禁用和最大输入长度,并获取焦点。
- input输入框有3个常用的事件:键盘输入事件(bindinput)、输入框
聚焦事件(bindfocus)、输入框失去焦点事件(bindblur)。
下面演示input组件的使用方法。
(1)在WXML文件中利用input组件进行布局,示例代码如下:
<view style="margin:10px">
<view class="section">
<input placeholder="这是一个可以自动聚焦的input" auto-focus/>
</view>
<view class="section">
<input placeholder="只有在点击按钮的时候才聚焦" focus="{{focus}}" />
<view class="btn-area">
<button bindtap="bindButtonTap">使得输入框获取焦点</button>
</view>
</view>
<view class="section">
<input maxlength="10" placeholder="最大输入长度10" />
</view>
<view class="section">
<view class="section__title">你输入的是:{{inputValue}}</view>
<input bindinput="bindKeyInput" placeholder="输入同步到view中" />
</view>
<view class="section">
<input bindinput="bindReplaceInput" placeholder="连续的两个1会变成2" />
</view>
view class="section">
<input bindinput="bindHideKeyboard" placeholder="输入123自动收起键盘" />
</view>
<view class="section">
<input password type="number" />
</view>
<view class="section">
<input password type="text" />
</view>
<view class="section">
<input type="digit" placeholder="带小数点的数字键盘" />
</view>
<view class="section">
<input type="idcard" placeholder="身份证输入键盘" />
</view>
<view class="section">
<input placeholder-style="color:red" placeholder="占位符字体是红色的" />
</view>
</view>
(2)在JS文件中给input组件添加相应的事件并提供数据,示例代码如下:
Page({
data: {
focus: false,
inputValue: ' '
},
bindButtonTap: function() {
this.setData({
focus: true
})
},
bindKeyInput: function(e) {
this.setData({
inputValue: e.detail.value
})
},
bindReplaceInput: function(e) {
var value = e.detail.value
var pos = e.detail.cursor
if(pos != -1){
//光标在中间
var left = e.detail.value.slice(0, pos)
//计算光标的位置
pos = left.replace(/11/g, '2').length
}
//直接返回对象,可以对输入进行过滤处理,还可以控制光标的位置
return {
value: value.replace(/11/g, '2'),
cursor: pos
}
//或者直接返回字符串,光标在最后面
//return value.replace(/11/g, '2'),
},
bindHideKeyboard: function(e) {
if (e.detail.value === '123') {
//收起键盘
wx.hideKeyboard()
}
}
})
input组件的应用效果如图5.6所示。

图5.6 input组件的应用效果

注意
input组件是一个原生(native)组件,字体是系统字体,所以无法设置font-family;在input输入框聚焦期间,应避免使用CSS动画;confirm-type的最终表现效果与手机输入法本身的实现
有关,可能不支持或不完全支持部分Android系统输入法和第三方输入法;对于将input输入框封装在自定义组件中,而form组件在自定义组件外的情况,form组件将不能获得这个自定义组
件中input输入框的值,此时需要使用自定义组件的内置behaviors:[wx://form-field];若键盘
高度发生变化,keyboardheightchange事件可能会多次触发,开发者应该忽略掉相同的height 值。
5.1.5 多行输入框组件textarea
Textarea组件是用来输入多行文本内容的多行输入框组件,它的属性如表5.5所示。
表5.5 textarea组件的属性属性类型默认值说明valuestringtextarea输入框的内容
placeholderstringtextarea输入框为空时的占位符placeholder-stylestring指定placeholder的样式。目前仅支持
color、font-size和font-weightplaceholder-classstringtextarea-placeholder指定placeholder的样式类
disabledbooleanfalse指定是否禁用maxlengthnumber140指定最大输入长度,设置为-1的时候不限制最大长度
auto-focusbooleanfalse指定是否自动聚焦,唤起键盘focusbooleanfalse指定是否获取焦点auto-
heightbooleanfalse指定是否自动增高,设置auto-height时,style.height不生效confirm-typestringreturn设置键盘
右下角按钮的文字。send表示右下角按钮为“发送”,search表示右下角按钮为“搜索”,next表示右下角按钮为“下
一个”,go表示右下角按钮为“前往”,done表示右下角按钮为“完成”,return表示右下角按钮为“换行”confirm-
holdbooleanfalse点击键盘右下角按钮时是否保持键盘不收起adjust-keyboard-tobooleancursor键盘对齐位置。
cursor表示对齐光标位置,bottom表示对齐textarea输入框底部bindkeyboardheight-changeeventhandle键盘高度
发生变化的时候触发,event.detail = {height: height, duration: duration}bindlinechangeeventhandletextarea输
入框行数变化时调用,event.detail = {height: 0, heightRpx: 0, lineCount: 0}bindinputeventhandle用户使用键盘
输入时,触发input事件,event.detail = {value: value}。处理函数可以直接return一个字符串,将替换输入框中
的内容bindfocuseventhandletextarea输入框聚焦时触发,
event.detail = {value: value}bindblureventhandletextarea输入框失去焦点时触发,
event.detail = {value: value}bindconfirmeventhandle点击“完成”按钮时触发,event.detail = {value: value}
从表5.5中可以看出以下几点。
- 可以用placeholder来给textarea输入框添加提示信息,用placeholder-
style设置提示信息的样式,用placeholder-class设置提示信息的class,然后再针对这个class添加样式。
- 可以设置textarea输入框是否禁用和最大输入长度,并获取焦点,还
可设置自动调整行高。
- textarea输入框有4个常用的事件:键盘输入事件(bindinput)、输入
框聚焦事件(bindfocus)、输入框失去焦点事件(bindblur)、行数变化事件(bindlinechange)。
示例代码如下:
<view class="section">
<textarea bindblur="bindTextAreaBlur" auto-height placeholder="自动变高" />
</view>
<view class="section">
<textarea placeholder="placeholder颜色是红色的" placeholder-style="color:red;" />
</view>

注意
textarea输入框的blur事件会晚于页面上的tap事件,如果需要从button组件的单击事件获取 textarea输入框中的值,可以使用form组件的bindsubmit事件;不建议在多行文本上对用户的
输入进行修改,因为textarea输入框的bindinput事件并不会将返回值反映到textarea输入框上;若键盘高度发生变化,keyboardheightchange事件可能会多次触发,开发者应该忽略掉相
同的height值。
5.1.6 改进表单可用性组件label
label组件用来改进表单的可用性,包含button、checkbox、radio和 switch组件。label组件只有一个属性for,用来绑定控件的id。label组
件的使用方法有两种:一种没有定义for属性,另一种定义了for属性。
1.label组件没有定义for属性
label组件没有定义for属性时,包含button、checkbox、radio和switch 这些组件,点击label组件时,会触发label组件内第一个组件的事件。
假如button组件在第一个位置,就会触发button组件对应的事件;假如 radio组件在第一个位置,就会触发radio组件对应的事件。
下面演示没有定义for属性的label组件的使用方法。
(1)在WXML文件里利用label组件布局,把第一个组件隐藏起来,示例代码如下:
<label>
<button bindtap="clickBtn" hidden>我是button按钮</button>
<view>我是label组件内的内容</view>
<checkbox-group bindchange="checkboxChange">
<checkbox value="中国" />中国
<checkbox value="美国" />美国
</checkbox-group>
<radio-group bindchange="radioChange">
<radio value="男"/>男
<radio value="女"/>女
</radio-group>
</label>
(2)在JS文件里添加clickBtn()、checkboxChange()、radioChange()
这3个事件,分别输出不同的信息,示例代码如下:
Page({
clickBtn:function(){
console.log("点击了按钮组件");
},
checkboxChange:function(){
console.log("点击了多选项目组件");
},
radioChange:function(){
console.log("点击了单选项目组件");
}
})
(3)可以看到button组件是隐藏起来的,但点击“我是label组件内的内容”后,可以看到输出信息是按钮事件函数的信息,如图5.7所示。

图5.7 没有定义for属性的label组件的输出信息
从这里可以看出,当label组件内有多个组件时,会触发第一个组件的事件。
2.label组件定义了for属性
label组件定义了for属性后,会根据for属性的值找到和label组件id一样的组件,然后触发这个组件的相应事件。
下面演示定义了for属性的label组件的使用方法。
(1)在WXML文件里利用label组件布局,把第一个组件隐藏起来,给 label组件定义for="man",示例代码如下:
<label for="man">
<button id="btn" bindtap="clickBtn" hidden>我是button按钮</button>
<view>我是label组件内的内容</view>
<checkbox-group bindchange="checkboxChange"id="checkbox">
<checkbox value="中国" />中国
<checkbox value="美国" />美国
</checkbox-group>
<radio-group bindchange="radioChange" >
<radio id="man" value="男"/>男
<radio id="women" value="女"/>女
</radio-group>
</label>
(2)在JS文件里添加clickBtn()、checkboxChange()、radioChange()
这3个事件,分别输出不同的信息,示例代码如下:
Page({
clickBtn:function(){
console.log("点击了按钮组件");
},
checkboxChange:function(){
console.log("点击了多选项目组件");
},
radioChange:function(){
console.log("点击了单选项目组件");
}
})
(3)可以看到button组件是隐藏起来的,但点击“我是label组件内的内容”后,可以看到id为man的单选项目组件呈现选中状态,并触发事
件、输出信息,如图5.8所示。

图5.8 定义了for属性的label组件的输出信息
综上所述,如果label组件定义了for属性,它会根据for属性的值找到和 label组件id一样的组件,然后触发相应事件;如果label组件没有定义
for属性,它会找到label组件内的第一个组件,然后触发相应事件。
5.1.7 滚动选择器组件picker
picker组件主要支持5种滚动选择器:普通选择器、时间选择器、日期选择器、多列选择器和省市区选择器。默认是普通选择器。另外,还
有一种嵌入页面滚动选择器,支持将滚动选择器嵌入页面。
常用的5种滚动选择器是通过mode来区分的,普通选择器 mode="selector"、时间选择器mode="time"、日期选择器
mode="date"、多列选择器mode="multiSelector"、省市区选择器 mode="region",每种类型选择器的属性不同。
1.普通选择器:mode="selector"
普通选择器的属性如表5.6所示。
表5.6 普通选择器的属性属性类型默认值说明rangearray/object array[ ]mode为selector或
multiSelector时有效range-keystring当range是一个对象数组(Object Array)时,通过range-key来指定Object中
key的值作为普通选择器的显示内容valuenumber0表示选择了range中的第几项(下标从0开始)
bindchangeeventhandlevalue改变时触发change事件,event.detail={value}
示例代码如下:
<view class="section">
<view class="section__title">普通选择器</view>
<picker bindchange="bindPickerChange" value="{{index}}" range="{{array}}">
<view class="picker">
当前选择:{{array[index]}}
</view>
</picker>
</view>
Page({
data: {
array: ['美国', '中国', '巴西', '日本'],
objectArray: [
{
id: 0,
name: '美国'
},
{
id: 1,
name: '中国'
},
{
id: 2,
name: '巴西'
},
{
id: 3,
name: '日本'
}
],
index: 0
},
bindPickerChange: function(e) {
console.log('picker发送选择改变,携带值为', e.detail.value)
this.setData({
index: e.detail.value
})
}
})
普通选择器效果如图5.9所示。

图5.9 普通选择器效果
2.时间选择器:mode="time"
时间选择器的属性如表5.7所示。
表5.7 时间选择器的属性属性类型默认值说明valuestring表示选中的时间,格式
为"hh:mm"startstring表示有效时间范围的开始,格式为"hh:mm"endstring表示有效时间范围的结束,格式
为"hh:mm"bindchangeeventhandlevalue改变时触发change事件,
event.detail = {value: value}disabledbooleanfalse指定是否禁用
示例代码如下:
<view class="section">
<view class="section__title">时间选择器</view>
<picker mode="time" value="{{time}}" start="09:01" end="21:01" bindchange=
"bindTimeChange">
<view class="picker">
当前选择:{{time}}
</view>
</picker>
</view>
Page({
data: {
time: '12:01'
},
bindTimeChange: function(e) {
this.setData({
time: e.detail.value
})
}
})
时间选择器效果如图5.10所示。

图5.10 时间选择器效果
3.日期选择器:mode="date"
日期选择器的属性如表5.8所示。
表5.8 日期选择器的属性属性类型默认值说明valuestring0表示选中的日期,格式为"YYYY-MM-
DD"startstring表示有效日期范围的开始,格式为"YYYY-MM-DD"endstring表示有效日期范围的结束,格式
为"YYYY-MM-DD"fieldsstringday有效值为year、month、day,表示日期选择器的粒度
bindchangeeventhandlevalue改变时触发change事件,event.detail = {value: value}
示例代码如下:
<view class="section">
<view class="section__title">日期选择器</view>
<picker mode="date" value="{{date}}" start="2023-06-01" end="2023-09- 01"bindchange= "bindDateChange">
<view class="picker">
当前选择:{{date}}
</view>
</picker>
</view>
Page({
data: {
date: '2023-07-01'
},
bindDateChange: function(e) {
this.setData({
date: e.detail.value
})
}
})
日期选择器效果如图5.11所示。

图5.11 日期选择器效果
4.多列选择器:mode="multiSelector"
多列选择器的属性如表5.9所示。
表5.9 多列选择器的属性属性类型默认值说明rangearray/object array[ ]mode为selector或
multiSelector时有效range-keystring当range是一个对象数组时,通过range-key来指定Object中key的值作为多
列选择器的显示内容valuenumber0表示选择了range中的第几项(下标从0开始)bindchangeeventhandlevalue
改变时触发change事件,event.detail={value}bindcolumnchangeeventhandle列发生改变时触发
示例代码如下:
<view class="section">
<view class="section__title">多列选择器</view>
<picker mode="multiSelector" bindchange="bindMultiPickerChange" bindcolumnchange=
"bindMultiPickerColumnChange" value="{{multiIndex}}" range="{{multiArray}}">
<view class="picker">
当前选择:{{multiArray[0][multiIndex[0]]}}, {{multiArray[1][multiIndex[1]]}},
{{multiArray[2][multiIndex[2]]}}
</view>
</picker>
</view>
Page({
data: {
multiArray: [['无脊椎动物', '脊椎动物'], ['扁形动物', '线形动物', '环节动物', '软体动物', '节肢动物'], ['猪带绦虫', '血吸虫']],
objectMultiArray: [
[
{
id: 0,
name: '无脊椎动物'
},
{
id: 1,
name: '脊椎动物'
}
], [
{
id: 0,
name: '扁形动物'
},
{
id: 1,
name: '线形动物'
},
{
id: 2,
name: '环节动物'
},
{
id: 3,
name: '软体动物'
},
{
id: 3,
name: '节肢动物'
}
], [
{
id: 0,
name: '猪带绦虫'
},
{
id: 1,
name: '血吸虫'
}
]
],
multiIndex: [0, 0, 0]
},
bindMultiPickerChange: function (e) {
console.log('picker发送选择改变,携带值为', e.detail.value)
this.setData({
multiIndex: e.detail.value
})
},
bindMultiPickerColumnChange: function (e) {
console.log('修改的列为', e.detail.column, ', 值为', e.detail.value);
var data = {
multiArray: this.data.multiArray,
multiIndex: this.data.multiIndex
};
data.multiIndex[e.detail.column] = e.detail.value;
switch (e.detail.column) {
case 0:
switch (data.multiIndex[0]) {
case 0:
data.multiArray[1] = ['扁形动物', '线形动物', '环节动物', '软体动物', '节肢动物'];
data.multiArray[2] = ['猪带绦虫', '血吸虫'];
break;
case 1:
data.multiArray[1] = ['鱼', '两栖动物', '爬行动物'];
data.multiArray[2] = ['鲫鱼', '带鱼'];
break;
}
data.multiIndex[1] = 0;
data.multiIndex[2] = 0;
break;
case 1:
switch (data.multiIndex[0]) {
case 0:
switch (data.multiIndex[1]) {
case 0:
data.multiArray[2] = ['猪带绦虫', '血吸虫'];
break;
case 1:
data.multiArray[2] = ['蛔虫'];
break;
case 2:
data.multiArray[2] = ['蚂蚁', '蚂蟥'];
break;
case 3:
data.multiArray[2] = ['河蚌', '蜗牛', '蛞蝓'];
break;
case 4:
data.multiArray[2] = ['昆虫', '甲壳动物', '蛛形动物', '多足动物'];
break;
}
break;
case 1:
switch (data.multiIndex[1]) {
case 0:
data.multiArray[2] = ['鲫鱼', '带鱼'];
break;
case 1:
data.multiArray[2] = ['⻘蛙', '大鲵'];
break;
case 2:
data.multiArray[2] = ['蜥蜴', '龟', '壁虎'];
break;
}
break;
}
data.multiIndex[2] = 0;
break;
}
console.log(data.multiIndex);
this.setData(data);
}
})
多列选择器效果如图5.12所示。

图5.12 多列选择器效果
5.省市区选择器:mode="region"
省市区选择器的属性如表5.10所示。
表5.10 省市区选择器的属性属性类型默认值说明valuestring[ ]表示选中的省、市、区,默认选
中每一列的第一个值custom-itemstring在每一列的顶部添加一个自定义的项bindchangeeventhandlevalue改变时
触发change事件,event.detail = {value, code, postcode},其中字段code是统计用区划代码,postcode是邮政
编码
示例代码如下:
<view class="section">
<view class="section__title">省市区选择器</view>
<picker mode="region" bindchange="bindRegionChange" value="{{region}}"
custom-item="{{customItem}}">
<view class="picker">
当前选择:{{region[0]}}, {{region[1]}}, {{region[2]}}
</view>
</picker>
</view>
Page({
data: {
region: ['广东省', '广州市', '海珠区'],
customItem: '全部'
},
bindRegionChange: function (e) {
console.log('picker发送选择改变,携带值为', e.detail.value)
this.setData({
region: e.detail.value
})
}
})
省市区选择器效果如图5.13所示。

图5.13 省市区选择器效果
6.嵌入页面滚动选择器
嵌入页面滚动选择器使用picker-view组件在页面里进行布局,图5.14 展示了嵌入页面滚动选择器。

图5.14 嵌入页面滚动选择器
嵌入页面滚动选择器中只能使用picker-view-column组件,其属性如表 5.11所示。
表5.11 嵌入页面滚动选择器的属性属性类型说明valuearray.<number>数组中的数字依次
表示选择器内的picker-view-column选择的第几项(下标从0开始),数字大于picker-view-column可选项数量
时,选择最后一项indicator-stylestring设置选择器中间选中框的样式indicator-classstring设置选择器中间选中框
的类名mask-stylestring设置蒙层的样式mask-classstring设置蒙层的类名bindchangeeventHandle滚动选择时触
发change事件,event.detail = {value};value为数组,表示选择器内的picker-view-column当前选择的是第几项
(下标从0开始)bindpickstarteventhandle滚动选择开始时触发bindpickendeventhandle滚动选择结束时触发
示例代码如下:
<view>
<view style="text-align:center">{{year}}年{{month}}月{{day}}日</view>
<picker-view indicator-style="height: 50px;" style="width: 100%; height: 300px;" value="
{{value}}" bindchange= "bindChange">
<picker-view-column>
<view wx:for="{{years}}" style="line-height: 50px">{{item}}年</view>
</picker-view-column>
<picker-view-column>
<view wx:for="{{months}}" style="line-height: 50px">{{item}}月</view>
</picker-view-column>
<picker-view-column>
<view wx:for="{{days}}" style="line-height: 50px">{{item}}日</view>
</picker-view-column>
</picker-view>
</view>
const date = new Date()
const years = [ ]
const months = [ ]
const days = [ ]
for (let i = 1990; i <= date.getFullYear(); i++) {
years.push(i)
}
for (let i = 1 ; i <= 12; i++) {
months.push(i)
}
for (let i = 1 ; i <= 31; i++) {
days.push(i)
}
Page({
data: {
years: years,
year: date.getFullYear(),
months: months,
month: 2,
days: days,
day: 2,
year: date.getFullYear(),
value: [9999, 1, 1],
},
bindChange: function(e) {
const val = e.detail.value
this.setData({
year: this.data.years[val[0]],
month: this.data.months[val[1]],
day: this.data.days[val[2]]
})
}
})
5.1.8 滑动选择器组件slider
slider组件常用于控制声音的大小、屏幕的亮度等,它可以设置滑动步长,显示当前值并设置最小值和最大值。
slider组件的属性如表5.12所示。
表5.12 slider组件的属性属性类型默认值说明minnumber0最小值maxnumber100最大值
stepnumber1步长,取值必须大于0,并且可被(max-min)整除disabledbooleanfalse指定是否禁用
valuenumber0当前取值colorcolor#e9e9e9背景条的颜色(请使用backgroundColor)selected-
colorcolor#1aad19已选择的颜色(请使用activeColor)activeColorcolor#1aad19已选择的颜色
backgroundColorcolor#e9e9e9背景条的颜色block-sizenumber28滑块的大小,取值范围为12〜28block-
colorcolor#ffffff滑块的颜色show-valuebooleanfalse指定是否显示当前valuebindchangeeventhandle完成一次拖
动后触发的事件,event.detail = {value: value}bindchangingeventhandle拖动过程中触发的事件,
event.detail = {value}
示例代码如下:
<view class="section section_gap">
<text class="section__title">设置step</text>
<view class="body-view">
<slider bindchange="sliderchange" step="5"/>
</view>
</view>
<view class="section section_gap">
<text class="section__title">显示当前value</text>
<view class="body-view">
<slider bindchange="sliderchange" show-value/>
</view>
</view>
<view class="section section_gap">
<text class="section__title">设置最小/最大值</text>
<view class="body-view">
<slider bindchange="sliderchange" min="50" max="200" show-value/>
</view>
</view>
<view class="section section_gap">
<text class="section__title">设置颜色</text>
<view class="body-view">
<slider bindchange="sliderchange" color="black" selected-color="red"/>
</view>
</view>
<view class="section section_gap">
<text class="section__title">禁用</text>
<view class="body-view">
<slider bindchange="sliderchange" disabled show-value/>
</view>
</view>
slider组件效果如图5.15所示。

图5.15 slider组件效果
5.1.9 开关选择器组件switch
switch组件有两个状态:开、关。在很多场景中都会用到这个组件,如微信设置里,就通过该组件来设置是否接收新消息通知、通知是否
显示消息详情、是否打开声音、是否开启振动等。
switch组件的属性如表5.13所示。
表5.13 switch组件的属性属性类型默认值说明checkedbooleanfalse指定是否选中
disabledbooleanfalse指定是否禁用typestringswitch指定样式,有效值为switch和
checkboxbindchangeeventhandlechecked改变时触发change事件,event.detail=
{value}colorstring#04BE02switch组件的颜色,同CSS中的color
示例代码如下:
<view style="background-color:#cccccc;height:600px;">
<view style="padding-top:10px;"></view>
<view style="display:flex;flex-direction:row;background-color:#ffffff;height: 50px; lineheight:50px;">
<view style="font-weight:bold;">接收新消息通知</view>
<view style="position:absolute;right:10px;">
<switch type="switch" checked/>
</view>
</view>
<view style="height:1px;background-color:#f2f2f2;opacity:0.2"></view>
<view style="display:flex;flex-direction:row;background-color:#ffffff;height: 50px; lineheight:50px;">
<view style="font-weight:bold;">通知显示消息详情</view>
<view style="position:absolute;right:10px;">
<switch type="switch"/>
</view>
</view>
<view style="height:1px;background-color:#f2f2f2;opacity:0.2"></view>
<view style="margin-top:20px;"></view>
<view style="height:1px;background-color:#f2f2f2;opacity:0.2"></view>
<view style="display:flex;flex-direction:row;background-color:#ffffff;height: 50px; lineheight:50px;">
<view style="font-weight:bold;">声音</view>
<view style="position:absolute;right:10px;">
<switch type="checkbox" checked/>
</view>
</view>
<view style="height:1px;background-color:#f2f2f2;opacity:0.2"></view>
<view style="height:1px;background-color:#f2f2f2;opacity:0.2"></view>
<view style="display:flex;flex-direction:row;background-color:#ffffff;height:50px;
line-height:50px;">
<view style="font-weight:bold;">振动</view>
<view style="position:absolute;right:10px;">
<switch type="checkbox"/>
</view>
</view>
<view style="height:1px;background-color:#f2f2f2;opacity:0.2"></view>
</view>
开关选择器组件的应用效果如图5.16所示。

图5.16 开关选择器组件的应用效果
5.1.10 表单组件form
form组件用来将表单中的值提交给JS文件进行处理,它可以提交 switch、input、checkbox、slider、radio、picker这些组件的值。提交
表单的时候,借助form-type为submit的button组件,可以将form组件中的value提交(需要在form组件中加上name来作为key)。form组件的
属性如表5.14所示。
表5.14 form组件的属性属性类型默认值说明report-submitbooleanfalse指定是否返回formId(用于
发送模板消息)report-submit-timeoutnumber0等待一段时间(单位为ms)以确认formId是否生效。如果未指定
这个参数,formId有很小的概率是无效的(如遇到网络未连接的情况)。指定这个参数可以检测formId是否有
效,以此作为这项检测的超时时间。如果失败,将返回requestFormId: fail开头的formIdbindsubmiteventhandle
携带form中的数据触发submit事件,event.detail = {value:{'name':'value'},formId:''}bindreseteventhandle表单
重置时会触发reset事件
示例代码如下:
<form bindsubmit="formSubmit" bindreset="formReset">
<view style="margin:10px;">
<view style="font-weight:bold;">switch开关选择器</view>
<switch name="switch"/>
</view>
<view style="margin:10px;">
<view style="font-weight:bold;">slider滑动选择器</view>
<slider name="slider" show-value ></slider>
</view>
<view style="margin:10px;">
<view style="font-weight:bold;">input输入框</view>
<input name="input" placeholder="请在这里输入" />
</view>
<view style="margin:10px;">
<view style="font-weight:bold;">radio单项选择器</view>
<radio-group name="radio-group">
<label><radio value="radio1"/>radio1</label>
<label><radio value="radio2"/>radio2</label>
</radio-group>
</view>
<view style="margin:10px;">
<view style="font-weight:bold;">checkbox多项选择器</view>
<checkbox-group name="checkbox">
<label><checkbox value="checkbox1"/>checkbox1</label>
<label><checkbox value="checkbox2"/>checkbox2</label>
</checkbox-group>
</view>
<view class="btn-area">
<button form-type="submit" type="primary">确定</button>
<button form-type="reset">重置</button>
</view>
</form>
Page({
formSubmit: function(e) {
console.log('form发生了submit事件,携带数据为:', e.detail.value)
},
formReset: function() {
console.log('form发生了reset事件')
}
})
未填写表单和填写表单后的效果如图5.17和图5.18所示。

图5.17 未填写表单的效果

图5.18 填写表单后的效果
点击重置按钮可以重置表单,点击确定按钮可以把表单数据提交到JS 文件进行处理,图5.18中表单提交的数据如图5.19所示。

图5.19 表单提交的数据
5.1.11 项目实战:使用AI编程工具辅助实现注册页面
1
.任务目标
使用通义灵码辅助实现莫凡商城小程序的注册页面。
2.任务实施
下面来实现莫凡商城小程序的注册页面。
(1)在app.json文件里添加注册页面路径“pages/register/register”。
(2)打开通义灵码,输入以下内容并发送,如图5.20所示。

图5.20 发送需求
在微信小程序中实现注册页面,注册部分字段有用户名、手机号、密码、确认密码、昵称,绑定这些输入框的数据,label跟输入框水平居
中展示,每行高为40px,最下面是“注册”按钮,点击“注册”按钮,如果字段为空,则提示必填项不能为空,最后把获得的数据传递给注册接
口。
3.AI生成
通义灵码根据需求生成了实现注册页面的代码,包括WXML布局、 WXSS样式及JS数据绑定,实现了注册过程非空判断、点击按钮进行注
册的功能,如图5.21所示。

图5.21 通义灵码生成注册页面
4.优化建议
在运行AI生成的代码后,发现其结果与我们的实际需求还有一定的差距,可以从以下几个方面进行优化。
- 对需求进行更加细致的描述后再次进行生成,例如给出输入框的宽度
以及输入框之间的间距。
- 点击事件实现注册功能时,把生成的示例接口替换成我们自己的真实
接口,并根据真实接口返回的数据格式进行修改。
- 根据自己的实际需求手动进行调整,可以对页面中输入框的样式、输
入框之间的间距、文字的大小等进行调整,使页面更加美观。
5.页面展示
代码经过优化后,运行代码,页面样式如图5.22所示。

图5.22 注册页面
5.2微信小程序界面交互API
微信小程序界面交互API包括wx.showToast()、wx.hideToast()、 wx. showModal()、wx.showLoading()、wx.hideLoading()、
wx.showA ctionSheet()。使用这些界面交互API,可以给用户创造良好的使用体验,提供提示信息。
5.2.1 显示/隐藏消息提示框API
wx.showToast()用来显示消息提示框,wx.hideToast()用来隐藏消息提示框。
wx.showToast()的参数说明如表5.15所示。
表5.15 wx.showToast()的参数说明属性类型默认值说明titlestring提示的内容
iconstring'success'图标,success表示显示成功图标,此时title最多显示7个汉字长度;loading表示显示加载中图
标,此时title最多显示7个汉字长度;none表示不显示图标,此时title最多可显示两行imagestring自定义图片图标
的本地路径,image的优先级高于icondurationnumber1500提示的延迟时间 maskbooleanfalse指定是否显示透明
蒙层,防止触摸穿透successfunction接口调用成功的回调函数failfunction接口调用失败的回调函数
completefunction接口调用结束的回调函数(调用成功、失败都会执行)
wx.hideToast()的参数说明如表5.16所示。
表5.16 wx.hideToast()的参数说明属性类型默认值说明noConflictbooleanfalse目前toast和
loading相关接口可以相互混用,此参数可用于取消混用特性successfunction接口调用成功的回调函数failfunction
接口调用失败的回调函数completefunction接口调用结束的回调函数(调用成功、失败都会执行)
示例代码如下:
Page({
onLoad:function(){
//显示成功图标
wx.showToast({
title: '成功',
icon: 'success',
duration: 2000
})
//显示加载中图标
wx.showToast({
title: '加载中',
icon: 'loading',
duration: 2000
})
//不显示icon图标
wx.showToast({
title: '不显示icon',
icon: 'none',
duration: 2000
})
//显示图片图标
wx.showToast({
title: '图片图标',
icon: 'none',
image:'../images/icon/payyes.jpg',
duration: 2000
})
//隐藏提示信息
wx.hideToast();
}
})
图标的显示效果如图5.23〜图5.26所示。

图5.23 显示成功图标

图5.24 显示加载中图标

图5.25 不显示jcon图标

图5.26 图片图标
5.2.2 显示模态对话框API
wx.showModal()用来显示模态对话框,其参数说明如表5.17所示。
表5.17 wx.showModal()的参数说明属性类型默认值说明titlestring提示的标题contentstring
提示的内容showCancelbooleantrue指定是否显示“取消”按钮cancelTextstring'取消'“取消”按钮的文字,最多4个字
符 cancelColorstring#000000“取消”按钮的文字颜色,必须是十六进制格式的颜色字符串confirmTextstring'确
定'“确定”按钮的文字,最多4个字符confirmColorstring#576B95“确定”按钮的文字颜色,必须是十六进制格式的
颜色字符串successfunction接口调用成功的回调函数failfunction接口调用失败的回调函数completefunction接口调
用结束的回调函数(调用成功、失败都会执行)
示例代码如下:
Page({
onLoad:function(){
wx.showModal({
title: '温馨提示',
content: '这是一个模态对话框',
success(res) {
if (res.confirm) {
console.log('用户点击确定')
} else if (res.cancel) {
console.log('用户点击取消')
}
}
})
}
})
模态对话框效果如图5.27所示。

图5.27 模态对话框效果
5.2.3 显示/隐藏loading提示框API
wx.showLoading()用来显示loading提示框,wx.hideLoading()用来隐藏 loading提示框。wx.showLoading()的参数说明如表5.18所示。
表5.18 wx.showLoading的参数说明属性类型默认值说明titlestring提示的内容
maskbooleanfalse是否显示透明蒙层,防止触摸穿透successfunction接口调用成功的回调函数failfunction接口调
用失败的回调函数completefunction接口调用结束的回调函数(调用成功、失败都会执行)
wx.hideLoading()的参数说明如表5.19所示。
表5.19 wx.hideLoading的参数说明属性类型默认值说明noConflictbooleanfalse目前toast和
loading相关接口可以相互混用,此参数可用于取消混用特性successfunction接口调用成功的回调函数failfunction
接口调用失败的回调函数completefunction接口调用结束的回调函数(调用成功、失败都会执行)
示例代码如下:
Page({
onLoad:function(){
//显示loading提示框
wx.showLoading({
title: '加载中',
})
//隐藏loading提示框
wx.hideLoading();
}
})
loading提示框效果如图5.28所示。

图5.28 loading提示框效果
5.2.4 显示操作菜单API
wx.showActionSheet()用来显示操作菜单,最多显示6个,其参数说明如表5.20所示。
表5.20 wx.showActionSheet()的参数说明属性类型默认值说明itemListarray.<string>按
钮的文字数组,数组长度最大为6itemColorstring#000000按钮的文字颜色successfunction接口调用成功的回调函
数failfunction接口调用失败的回调函数completefunction接口调用结束的回调函数(调用成功、失败都会执行)
示例代码如下:
Page({
onLoad:function(){
wx.showActionSheet({
itemList: ['小学', '初中', '高中', '大学'],
success(res) {
console.log(res.tapIndex)
},
fail(res) {
console.log(res.errMsg)
}
})
}
})
操作菜单效果如图5.29所示。

图5.29 操作菜单效果
5.3定时器API
微信小程序提供了定时器API,可以用两种方式设置定时器:一种是使用setTimeout(),在定时到达设定的时间以后执行注册的回调函数;另
一种是使用setInterval(),按照指定的周期(以毫秒计)来执行注册的回调函数。这两种方式的区别在于,setTimeout()是达到设定时间后执
行一次,如定时5分钟,那么在5分钟后这个定时器就执行一次;
setInterval()是按照设定的周期来执行,如设置每5分钟执行一次,那么每间隔5分钟定时器就会执行一次。下面是定时器用到的API。
- setTimeout(function callback, number delay, any rest):设定一个定
时器,在定时到达设定的时间以后执行注册的回调函数。
参数说明:callback为回调函数;delay为延迟的时间(以毫秒计),函数的调用会在该延迟之后发生;rest为附加参数,会作为参数传递给回
调函数;返回值为number,即定时器的ID,这个值可以传递给 clearTimeout()来取消该定时器。
- clearTimeout(number timeoutID):取消由setTimeout()设置的定时
器。
参数说明:timeoutID为要取消的定时器的ID。
- setInterval(function callback, number delay, any rest):设定一个定
时器,按照指定的周期(以毫秒计)来执行注册的回调函数。
参数说明:callback为回调函数;delay为执行两次回调函数的时间间隔;rest为附加参数,会作为参数传递给回调函数;返回值为
number,即定时器的ID,这个值可以传递给clearInterval()来取消该定时器。
- clearInterval(number intervalID):取消由setInterval()设置的定时
器。
参数说明:intervalID为要取消的定时器的ID。
示例代码如下:
Page({
onLoad:function(){
var number1 = setTimeout(this.initTimeout, 1000, { "name": "小刚" });//启动setTimeout 定时器
var number2 = setInterval(this.initInterval, 1000, { "name": "小刚" });//启动setInterval定时器
//clearTimeout(number1);//取消由setTimeout设置的定时器
//clearInterval(number2);//取消由setInterval设置的定时器
},
initTimeout:function(res){
console.log('setTimeout定时器启动-----------------');
console.log('setTimeout定时器返回值如下:');
console.log(res);
},
initInterval:function(res){
console.log('setInterval定时器启动----------------');
console.log('setInterval定时器返回值如下:');
console.log(res);
}
})
输出日志如图5.30所示。

图5.30 输出日志
5.4数据缓存API
微信小程序提供数据本地缓存功能,如可以将用户信息缓存到本地,这样就不用每次调用服务器来获取这些信息了。数据缓存API可以将所
需数据缓存到本地,还可以获取本地缓存的数据、移除缓存数据及清理本地缓存数据。
5.4.1 将数据缓存到本地
微信小程序为数据缓存到本地提供了两种方式:wx.setStorage()以异步方式将数据存储在本地缓存指定的key中;wx.setStorageSync()以同
步方式将数据存储在本地缓存指定的key中。除非用户主动删除或因存储空间不足而被系统清理,否则缓存的数据就一直可用。单个key允许
存储的最大数据量为1MB,所有数据的存储上限为10MB。
下面用两种不同的方式把用户信息缓存到本地,示例代码如下:
Page({
data: {
user: {
id: '10000',
name: 'lihua',
userName :'李华'
}
},
onLoad: function () {
wx.setStorage({
key: 'user',
data: this.data.user,
})
wx.setStorageSync('userSync', this.data.user);
},
})
在Storage里可以查看缓存的数据,如图5.31所示。

图5.31 本地缓存的数据
将数据缓存到本地,不管是以同步方式还是以异步方式,都是通过 key/value的形式存储数据的,只不过以同步方式缓存需要等本地缓存
成功后,才可以继续执行后面的程序,而以异步方式缓存则不需要等待本地缓存成功便可直接继续执行程序。在数据缓存比较耗时的情况
下,可以使用异步方式进行缓存,以保证程序顺利执行。
5.4.2 获取本地缓存数据
wx.getStorage()以异步方式从本地缓存中获取指定key对应的内容, wx.getStorageSync()以同步方式从本地缓存中获取指定key对应的内
容。
下面展示具体的使用方法,示例代码如下:
Page({
onLoad:function(){
wx.getStorage({
key: 'user',
success: function (res) {
console.log(res, 'res');
}
})
var userSync = wx.getStorageSync('userSync');
console.log(userSync, 'userSync');
}
})
获取到的本地缓存数据如图5.32所示。

图5.32 异步获取本地缓存数据
5.4.3 清理本地缓存数据
wx.removeStorage()、wx.removeStorageSync()用来从本地缓存中移除指定的key,wx.clearStorage()、wx.clearStorageSync()用来清理本
地缓存数据。
1.wx.removeStorage()
wx.removeStorage()用来异步从本地缓存中移除指定的key。
在移除前可以看到本地缓存中有key为user的数据,如图5.33所示。

图5.33 key为user的缓存数据
下面从本地缓存中移除key为user的数据,示例代码如下:
Page({
onLoad:function(){
//异步移除key为user的数据
wx.removeStorage({
key: 'user',
success: function(res){
console.log(res);
},
})
}
})
移除后,在本地缓存列表里就找不到key为user的缓存数据了。
2.wx.removeStorageSync()
wx.removeStorageSync()用来同步从本地缓存中移除指定的key,它的作用和wx.removeStorage()一样。
示例代码如下:
Page({
onLoad:function(){
//同步移除key为userSync的数据
wx.removeStorageSync('userSync');
}
})
3.wx.clearStorage()和wx.clearStorageSync()
wx.clearStorage()和wx.clearStorageSync()用来清理本地所有缓存数据,前者是以异步方式,后者是以同步方式。
示例代码如下:
wx.clearStorage()
try {
wx.clearStorageSync()
} catch(e) {
}
5.5登录相关API
微信小程序登录需要使用登录API、获取账号信息API、获取用户信息 API、授权API。
5.5.1 登录API
登录功能是小程序必不可少的功能,微信小程序也提供了登录API。登录微信小程序可以分为以下几个步骤。
(1)在微信小程序里使用wx.login()获取登录凭证code。
(2)将code和AppID、AppSecret(在微信公众平台中AppID的下面)、grant_type(授权类型)这 4 个参数发送到后台服务器上,在后
台服务器上请求路径https://api.weixin.qq.com/sns/jscode2session (该链接是微信请求的接口地址,直接打开不能使用,需要传递以上
参数后才能使用),同时传递这4个参数,就能获取唯一标识(openid)
和会话密钥(session_key)。
(3)拿到唯一标识和会话密钥后,在后台服务器上生成自己的 sessionId。
(4)微信小程序可以将服务器生成的sessionId信息保存到本地缓存(Storage)。
(5)后续用户进入微信小程序,先从本地缓存获得sessionId,将这个 sessionId传输到服务器上进行查询来维护登录状态。
下面详细讲解这些步骤。
1.用wx.login()获取登录凭证code
微信小程序使用wx.login()来获取登录凭证code,用户得到允许登录后,回调内容会带上code(有效时间为5分钟),开发者需要将code发
送到开发者服务器后台,以获取openid和session_key。
示例代码如下:
App({
onLaunch: function() {
wx.login({
success:function(res){
var code = res.code; //用户登录凭证
if(code){
console.log('获取用户登录凭证:'+code);
}else{
console.log('获取用户登录凭证失败');
}
}
})
}
})
2.将用户登录凭证发送至开发者服务器获得唯一标识
和会话密钥
开发者服务器需要提供一个后台接口来接收用户登录凭证code,示例代码如下:
App({
onLaunch: function() {
wx.login({
success:function(res){
var code = res.code;//用户登录凭证
if(code){
console.log('获取用户登录凭证:'+code);
wx.request({ //请求自己的后台服务器,传输用户登录凭证code
url: 'https://www.my-domain.com/wx/onlogin',
data: { code: code }
})
}else{
console.log('获取用户登录凭证失败');
}
}
})
}
})
开发者服务器接收到用户登录凭证code值后,用其和AppID、 AppSecret、grant_type参数去请求微信服务器接口
https://api.weixin.qq.com/sns/jscode2session,从而获取session_key 和openid。其中,session_key是对用户数据进行加密签名的密钥,为
了自身的应用安全,session_key不应该在网络上传输。
接口地址如下:
https://api.weixin.qq.com/sns/jscode2session?
appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
参数说明:appld为小程序唯一标识;secret是调用API的唯一凭证;
js_code为登录时获取的code;grant_type填写为“authorization_code”
(固定值)。
返回值说明:openid为用户在微信里的唯一标识;session_key为会话密钥。
后台服务器请求微信服务器代码的实现可以使用Java、PHP、C++、 Node.js等多种语言。
3.开发者服务器生成自己的sessionId
开发者服务器获取到openid和session_key后,需要生成自己的 sessionId,规则由自己制定,可以拼接成字符串,也可以拼接成字符
串后再用MD5加密等。生成的sessionId需要在开发者服务器中保存起来,小程序在校验登录或者遇到需要登录后才能执行的操作时,都需
要到开发者服务器中来验证。sessionId可以保存到Memcached、Redis 或内存中。
4.小程序客户端保存sessionId
小程序客户端是没有类似于浏览器客户端的cookie或session机制的,但是可以利用小程序的Storage缓存机制来保存sessionId,在需要登录
状态才能发起请求的时候传递这个参数,从而不用每次重新登录。在之后调用那些需要登录才有权限访问的后台服务时,可以将保存在
Storage中的sessionId取出并携带在请求中,传递到后台服务器,后台代码获取到该sessionId后,从缓存Redis或内存中查找是否有该
sessionId存在,存在即确认该session是有效的,继续执行后续的代码,否则进行错误处理。
5.用wx.checkSession()检查登录态是否过期
微信小程序可以使用wx.checkSession()来检查登录态是否过期,如果过期,就重新登录。
通过wx.login()获得的用户登录态拥有一定的时效性。用户越久未使用小程序,其登录态就越有可能失效;如果用户一直在使用小程序,则
其登录态将一直保持有效。具体时效逻辑由微信维护,对开发者透明。开发者只需要调用wx.checkSession()接口检测当前用户登录态是
否有效。
登录态过期后,开发者可以再调用wx.login()获取新的用户登录态。调用成功说明当前session_key未过期,调用失败则说明session_key已过
期。示例代码如下:
wx.checkSession({
success: function(){
//登录态未过期
},
fail: function(){
//登录态过期
wx.login()
}
})
5.5.2 获取账号信息API
微信小程序提供wx.getAccountInfoSync()来获取账号信息。账号信息包括miniProgram小程序账号信息和plugin插件账号信息(仅在插件中
调用时包含这一项)。miniProgram小程序账号信息包括小程序AppID, plugin插件账号信息包括插件AppID和插件版本号。
示例代码如下:
const accountInfo = wx.getAccountInfoSync();
console.log(accountInfo.miniProgram.appId) // 小程序AppID
console.log(accountInfo.plugin.appId) // 插件AppID
console.log(accountInfo.plugin.version) // 插件版本号,'a.b.c' 这样的形式
5.5.3 获取用户信息API
wx.getUserInfo()、wx.getUserProfile()这两个用来获取用户信息的接口已被回收,后续获取用户头像和昵称需要通过昵称填写来获取,自
2022年10月25日24时起(以下统称“生效期”),用户头像和昵称获取规则进行如下调整。
- 自生效期起,小程序wx.getUserProfile()接口被收回:在生效期后发
布的新版本小程序中,通过wx.getUserProfile()接口获取的用户头像将统一返回默认灰色头像,昵称将统一返回“微信用户”。生效期前发布的
小程序版本不受影响,但如果进行版本更新,则需要进行适配。
- 自生效期起,插件通过wx.getUserInfo()接口获取的用户头像和昵称
被收回:在生效期后发布的插件中,通过wx.getUserInfo()接口获取的用户头像将统一返回默认灰色头像,昵称将统一返回“微信用户”。生效
期前发布的插件版本不受影响,但如果进行版本更新,则需要进行适配。通过wx.login()与wx.getUserInfo()接口获取openld、unionld的能
力不受影响。
- “头像昵称填写能力”支持获取用户头像和昵称:如业务需获取用户头
像和昵称,可以使用“头像昵称填写能力(” 基础库2.21.2版本开始支持,覆盖iOS与Android微信8.0.16以上版本)。
- wx.getUserProfile()与wx.getUserInfo()接口兼容基础库2.27.1以下版
本的头像和昵称获取需求:对于来自低版本的基础库与微信客户端的访问,小程序通过wx.getUserProfile()接口正常返回用户头像和昵称,
插件通过wx.getUserInfo()接口正常返回用户头像和昵称,开发者可继续使用以上能力做向下兼容。
wx.getUserProfile()接口、wx.getUserInfo()接口、“头像昵称填写能力”
的基础库版本支持能力详细对比如表5.21所示。
表5.21 基础库版本支持能力对比基础库版本wx.getUserProfile()接口wx.getUserInfo()接口头
像昵称填写能力基础库2.27.1及以上版本不支持不支持支持基础库2.21.2〜2.27.0版本支持支持支持基础库2.10.4
〜2.21.0版本支持支持不支持基础库2.9.5及以下版本不支持支持不支持
示例代码如下:
<!--wxml-->
<button class="avatar" open-type="chooseAvatar" bind:chooseavatar=
"onChooseAvatar">
<image src="{{avatarUrl}}"></image>
</button>
<input type="nickname" class="weui-input" placeholder="请输入昵称"/>
/**wxss**/
.avatar{
width: 80px;
height: 80px;
padding:0;
background: none;
}
.avatar image{
width: 80px;
height: 80px;
border-radius: 100px;
}
.weui-input{
width: 90%;
height: 60px;
margin:20px auto;
background: #eee;
border-radius: 5px;
padding-left: 15px;
}
//js
const defaultAvatarUrl = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07 jQ odd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'
Page({
data: {
avatarUrl: defaultAvatarUrl,
},
onChooseAvatar(e) {
console.log(e)
const { avatarUrl } = e.detail
this.setData({
avatarUrl,
})
}
})
5.5.4 授权API
微信小程序部分API需要通过wx.authorize()来向用户发起授权请求,之后会立刻弹窗询问用户是否同意授权小程序使用某项功能或获取用
户的某些数据,但不会实际调用对应接口。如果用户之前已经同意授权,则不会出现弹窗,直接返回成功。可以使用wx.getSetting()获取用
户当前的授权状态。
打开设置界面,用户可以在小程序设置界面中控制对该小程序的授权状态。可以调用wx.openSetting()打开小程序设置界面,引导用户开启
授权。
打开小程序设置界面有以下两种实现方式。
- 使用button组件,示例代码如下:
<button open-type="openSetting"bindopensetting="callback">打开小程序设置界面 </button>
- 由点击行为触发wx.openSetting()接口的调用,示例代码如下:
<button bindtap="openSetting">打开小程序设置界面</button>
Page({
openSetting:function(){
wx.openSetting()
}
})
授权状态设置界面如图5.34所示。

图5.34 授权状态设置界面
授权接口wx.authorize()通过属性scope来设置授权,scope授权参数如表5.22所示。
表5.22 scope授权参数Scope授权参数接口说明scope.userLocationwx.getLocation(),
wx.startLocationUpdate()精确地理位置scope.userFuzzyLocationwx.getFuzzyLocation()模糊地理位置
scope.userLocationBackgroundwx.startLocationUpdateBackground()后台定位scope.werunwx.getWeRunData()
微信运动步数scope.recordlive-pusher组件,wx.startRecord(),wx.joinVoIPChat(),RecorderManager.start()麦
克风scope.writePhotosAlbumwx.saveImageToPhotosAlbum(),wx.saveVideoToPhotosAlbum()保存到相册
scope.cameracamera组件,live-pusher组件,wx.createVKSession()摄像头
scope.bluetoothwx.openBluetoothAdapter(),wx.createBLEPeripheralServer()蓝牙
scope.addPhoneContactwx.addPhoneContact()添加到联系人
scope.addPhoneCalendarwx.addPhoneRepeatCalendar(),wx.addPhoneCalendar()添加到日历
scope.addresswx.chooseAddress()通信地址(已取消授权,可以直接调用对应接口)
scope.invoiceTitlewx.chooseInvoiceTitle()发票抬头(已取消授权,可以直接调用对应接口)
scope.invoicewx.chooseInvoice()获取发票(已取消授权,可以直接调用对应接口)
scope.userInfowx.getUserInfo()用户信息(小程序已回收,小游戏可继续调用)
示例代码如下:
Page({
onLoad: function () {
// 可以先通过wx.getSetting()查询用户是否授权了“scope.record”这个scope
wx.getSetting({
success(res) {
if (!res.authSetting['scope.record']) {
wx.authorize({
scope: 'scope.record',
success() {
// 用户已经同意小程序使用麦克风功能,后续调用wx.startRecord()接口不会弹窗询问
wx.startRecord()
}
})
}
}
})
}
})
授权弹窗效果如图5.35所示。

图5.35 授权弹窗效果
5.6项目实战:使用AI编程工具辅助实现登录页面1
.任务目标
实现莫凡商城小程序的登录页面,学会实现登录页面要应用到的组件和API的使用方法,并能举一反三,实现其他类似的登录页面。
莫凡商城小程序的登录页面提供两种登录方式供用户选择:账号密码登录和手机验证码登录。
2.任务实施
下面来实现莫凡商城小程序的登录页面。
(1)在app.json文件里添加登录页面路径“pages/login/login”。
(2)在login.json文件里配置导航标题,示例代码如下:
{
"navigationBarTitleText": "登录"
}
(3)打开通义灵码,输入以下内容并发送,如图5.36所示。

图5.36 发送需求
实现微信小程序登录页面,该页面上有两种登录方式,可以通过点击切换,被选中的文字和底部边框变为绿色,一种是“账号密码登录”,输
入账号和密码,把值传给接口,账号和密码正确的话登录成功。另一种是“手机验证码登录”,输入手机号之后,点击“获取验证码”按钮,该
按钮在验证码输入框的右边,开始60秒倒计时。把手机号和验证码的值传给接口,正确的话登录成功。
3.AI生成
通义灵码根据需求生成了实现登录页面的代码,包括WXML布局、 WXSS样式及JS数据绑定,实现了切换登录方式、验证码倒计时及点击
按钮登录等功能,如图5.37所示。

图5.37 通义灵码实现登录页面
4.优化建议
在运行AI生成的代码后,发现其结果与我们的实际需求还有一定的差距,可以从以下几个方面进行优化。
- 对需求进行更加细致的描述后再次进行生成,例如详细描述两种登录
方式、详细描述60秒获取验证码的功能。
- 分模块进行生成,例如可以先生成“账号密码登录”模块,再进行“手
机验证码登录”模块的生成。
- 对AI编程工具生成的示例接口名称进行修改,替换成我们实际的接
口,并且根据实际接口的返回数据格式对返回值进行修改。
- 根据自己的实际需求手动调整代码,使页面更加美观。
5.页面展示
代码经过优化后,运行代码,页面样式如图5.38、图5.39所示。

图5.38 账号密码登录

图5.39 手机验证码登录
5.7项目实战:使用AI编程工具辅助实现从“我的”
页面跳转到登录页面1
.任务目标
进入“我的”页面,如果已经登录,则显示昵称,否则跳转到登录页面。
2.任务实施
打开通义灵码,实现判断是否登录的逻辑,如图5.40所示。

图5.40 通义灵码实现判断是否登录
JS示例代码如下:
Page({
/**
- 页面的初始数据
*/
data: {
nickname: '立即登录'
},
nav: function(e) {
var id = e.currentTarget.id;
var status = e.currentTarget.dataset.status;
wx.navigateTo({
url: '../myOrder/myOrder?id=' + id + '&status=' + status
})
},
/**
- 生命周期函数—监听页面加载
*/
onLoad(options) {
this.checkLoginStatus()
},
checkLoginStatus: function() {
// 获取本地缓存中的用户信息
const userInfo = wx.getStorageSync('userInfo');
if (userInfo && userInfo.nickName) {
// 已登录,设置昵称
this.setData({ nickname: userInfo.nickName });
} else {
// 未登录,跳转到登录页面
wx.redirectTo({
url: '/pages/login/login'
});
}
}
})
实现“我的”页面列表式导航功能时,要学会判断用户登录状态,在用户没有登录的时候跳转到登录页面,如图5.41所示,登录后显昵称。

图5.41 登录后页面
5.8项目实战:使用AI编程工具辅助实现修改密码
页面1
.任务目标
实现莫凡商城小程序的修改密码页面,学会通过表单组件来完成修改密码页面的设计,学会表单校验,实现修改密码功能。
莫凡商城小程序的修改密码页面包括原密码、新密码、确认新密码3个模块。
2.任务实施
下面来实现莫凡商城小程序的修改密码页面。
(1)在app.json文件里添加修改密码页面路径 “pages/updatePwd/updatePwd”。
(2)打开通义灵码,输入“在‘我的’界面点击修改密码跳转到修改密码页面,修改密码页面路径‘/pages/updstePwdjupdaiePwd’。只给出跳转
事件的逻辑就可以,其他的不用。”并发送,等待AI编程工具生成代码,如图5.42所示。

图5.42 通义灵码实现跳转到修改密码页面
(3)继续实现修改密码页面的布局和逻辑。打开通义灵码,输入以下内容并发送,如图5.43所示。

图5.43 发送需求
微信小程序实现修改密码页面,有3个字段,分别为原密码、新密码、确认新密码。输入不为空,点击“确认修改”按钮,把输入框的值传递给
修改密码接口。
3.AI生成
通义灵码根据需求生成了实现修改密码页面的代码,包括WXML布局、 WXSS样式及JS数据绑定,如图5.44所示。

图5.44 通义灵码生成修改密码页面
4.优化建议
在运行AI生成的代码后,发现其结果与我们的实际需求还有一定的差距,可以从以下几个方面进行优化。
- 对需求进行更加细致的描述后再次进行生成。
- 把修改密码的示例接口替换成我们自己的实际接口,根据实际接口返
回值的数据格式进行修改,当返回值的状态为成功时,提示密码修改成功。
- 根据自己的实际需求手动调整代码,使页面更加美观。
5.页面展示
代码经过优化后,运行代码,页面样式如图5.45所示。

图5.45 修改密码页面
5.9项目实战:使用AI编程工具辅助实现意见反馈
页面1
.任务目标
实现莫凡商城小程序的意见反馈页面,以便根据用户提交的意见反馈来改善小程序。
莫凡商城小程序的意见反馈页面包括意见反馈输入框和“提交”按钮。
2.任务实施
下面来实现莫凡商城小程序的意见反馈页面。
(1)在app.json文件里添加意见反馈页面路径 “pages/opinion/opinion”。
(2)在“我的”页面的列表式导航菜单的意见反馈处添加点击事件,与修改密码的点击事件类似。示例代码如下:
navigateoption() {
wx.navigateTo({
url: '/pages/option/option'
})
},
(3)使用通义灵码实现意见反馈页面布局及功能。打开通义灵码,输入以下内容并发送,如图5.46所示。

图5.46 发送需求
微信小程序实现意见反馈页面,包括意见反馈输入框和“提交”按钮两部分,意见反馈输入框使用textarea组件,点击“提交”按钮,获取到输入
框中的内容。
3.AI生成
通义灵码根据需求生成了实现意见反馈页面的代码,包括WXML布局、 WXSS样式及JS数据绑定,如图5.47所示。

图5.47 通义灵码生成意见反馈页面
4.优化建议
在运行AI生成的代码后,发现其结果与我们的实际需求还有一定的差距,可以从以下几个方面进行优化。
- 尽可能详细地描述需求,例如输入框的宽高、“提交”按钮的大小、背
景色等。
- 把生成的示例接口替换成实际接口,根据实际接口返回值的数据格式
进行修改,当返回值的状态为成功时,提示意见反馈成功。
- 根据自己的实际需求手动调整代码,使页面更加美观。
5.页面展示
代码经过优化后,运行代码,页面样式如图5.48所示。

图5.48 意见反馈页面
5.10项目实战:使用AI编程工具辅助实现清除缓
存功能1
.任务目标
实现清除缓存功能,学会清理小程序本地缓存数据。
2.任务实施
打开通义灵码,输入“微信小程序实现清除本地缓存,只给出实现方法即可”并发送,如图5.49所示。

图5.49 发送需求
3.AI生成
通义灵码根据需求生成了清除本地缓存数据的方法,如图5.50所示。

图5.50 通义灵码生成清除本地缓存数据方法
4.优化建议
可以在“清除缓存”按钮上添加点击事件并触发这个方法,查看清除缓存是否成功。