第3章〓豆豆云助教“我的”页面模块开发 网络安全(个人信息保护) 随着互联网的不断发展,数据传播得更快、更广,但同时也让数据沉淀,而被沉淀的个人信息的安全也成了一大问题。当今的时代,大数据与云计算相结合,可以通过用户的基本信息和操作行为,分析用户的行为、信用和偏好等。但是在商业利益的不断驱动下,这种被分析的信息数据很有可能被滥用而侵犯个人权利甚至危害国家安全。 2018年3月,Facebook被曝出超过5000万用户的个人信息资料泄露给英国“剑桥分析”公司,而这些被泄露的信息当中包括了用户的姓名、性别、年龄、爱好、种族、家庭住址、工作经历、教育背景、人际关系等各方面。在此次事件中,Facebook之所以受到谴责,一个重要原因就是未能保护好用户的信息数据,被怀疑有向第三方主动开放之嫌,使得个人数据被利益方所滥用,不仅侵害了个人合法权利,而且对国家民主产生了消极影响。Facebook数据泄露事件发生后,各方相关机构随即介入调查,但是涉事双方当事人各执一词,关于信息数据泄露也陷入罗生门怪圈。 随着互联网应用的普及和人们对互联网的依赖,互联网的安全问题也日益凸显。恶意程序、各类钓鱼和欺诈软件继续保持高速增长,同时黑客攻击和大规模的个人信息泄露事件频发,与各种网络攻击大幅增长相伴的是大量网民个人信息的泄露与财产损失的不断增加。 面对不断增长的网络风险,我们应当更加注重网络安全的守护,特别是对我们个人信息的保护。本章带领读者如何在小程序中实现对个人信息进行注册和登录的功能。首先,我们要完成授权登录页面和注册页面内容的开发,拥有授权信息与注册信息后,在“我的”页面将个人信息显示出来,“我的”页面模块开发是开发每一个小程序的基础模块,也是豆豆云助教收集用户信息的基础。 3.1授权登录页面 本节主要分为两部分,首先讲解授权登录页面涉及的知识点,然后在理解的情况下完成授权登录页面的开发。 观看视频 3.1.1授权页面知识点讲解 1. 小程序登录 小程序可以通过微信官方提供的登录能力方便地获取微信提供的用户身份标识,快速建立小程序内的用户体系。如图31所示,小程序通过wx.login()获取code,然后通过wx.request()发送code至开发者服务器,开发者服务器将登录凭证appid、appsecret与code用于校验微信接口,微信接口服务向开发者服务器返回用户唯一标识openid和会话密钥 session_key。开发者服务器实现自定义登录状态与openid、session_key关联,并向小程序返回自定义状态。小程序将自定义登录状态存入storage,并用于后续wx.request发起业务请求。 图31小程序登录流程时序 对于某个微信小程序,每个用户访问该小程序都要产生一个唯一的openid,这个openid为用户访问该小程序的标识符,即每个用户的openid都是不一样的。因此,可以把openid作为用户唯一标识符(类似身份证号),并存于数据库中用以后续操作。 开发者服务器与微信接口服务之间的交互是由后台实现的,本节主要以小程序前端与开发者服务器之间的交互为主,后台部分会在第9章中进行详细介绍。 2. wx.login() 调用wx.login()接口获取登录凭证(code),通过凭证进而换取用户登录态信息,其中wx.login()接口的属性如表31所示。 表31wx.login()接口的属性 属性类型是否必填说明 timeoutnumber否超时时间,单位为ms successfunction否接口调用成功的回调函数 failfunction否接口调用失败的回调函数 completefunction否接口调用结束的回调函数(无论调用成功或失败都会执行) 由于app.js会先于其他页面执行,因此比较适合处理一些注册函数,因此将wx.login()方法写在app.js文件中。 3. wx.request() wx.request()主要用于发送https网络请求,其属性详见表32。 表32wx.request()的属性 属性类型默认值是否必填说明 urlstring是开发者服务器接口地址 datastring/object/ ArrayBuffer否请求参数 headerobject否设置请求的 header,header 中不能设置 Referer。contenttype 默认为 application/json methodstringGET否http请求方法 dataTypestringjson否返回的数据格式 responseTypestringtext否响应的数据类型 successfunction否接口调用成功的回调函数 failfunction否接口调用失败的回调函数 completefunction否接口调用结束的回调函数(无论调用成功或失败都会执行) 这里以小程序登录中小程序向开发者服务器发送wx.request()请求为例,调用微信官方的wx.login()接口会返回一串jscode,服务器使用jscode、appid、appsecret三个参数向微信请求得到openid,这一步后台已经封装完成,并提供一个开放接口: https://zjgsujiaoxue.applinzi.com/index.php/Api/Weixin/code_to_openidv2。 具体代码如下: //登录 wx.login({ success: res => { //发送 res.code 到后台换取 openid, sessionkey, unionid wx.request({ url: 'https://zjgsujiaoxue.applinzi.com/index.php/Api/Weixin/code_to_openidv2', data: { 'code': res.code, 'from': 'wxbf9778a9934310a1' }, success: function (res) { console.log(res.data) //将sessionid保存到本地storage wx.setStorageSync('jiaoxue_OPENID', res.data.openid) }, fail: function (res) { console.log('res' + res) } }) } }) 上述代码中,通过wx.login()方法,成功返回res,其中res.code为微信官方返回的code,通过wx.request()发起请求,请求参数为code与appid,当请求成功时,后台会返回一个数组,数组中包含的值是由后台代码决定的,其中就包含了openid,这里可以使用console.log(res.data)来看一下返回的数组中所包含的值,如图32所示。 图32wx.request()请求的返回值 4. 数据缓存 每个微信小程序都可以有自己的本地缓存,通过数据缓存API可以对本地缓存进行设置、获取和清理。同一个微信用户,同一个小程序storage上限为 10MB。localStorage 以用户维度隔离,同一台设备上,A用户无法读取到B用户的数据。 注意,如果用户储存空间不足,微信会清空最近且最久未使用的小程序的本地缓存。因此不建议将关键信息全部存在localStorage,以防储存空间不足或用户换设备的情况。 数据缓存API主要有5类,包括数据的存储、获取、移除、清空,以及获取存储信息,每类均包含同步与异步两种,具体详见表33。 表33数据缓存API函数 函数说明 wx.setStorage(Object object)数据的存储(异步) wx.setStorageSync(string key,any data)数据的存储(同步) wx.getStorage(Object object)数据的获取(异步) wx.getStorageSync(string key)数据的获取(同步) wx.getStorageInfo(Object object)存储信息的获取(异步) wx.getStorageInfoSync()存储信息的获取(同步) wx.removeStorage(Object object)数据的移除(异步) wx.removeStorageSync(string key)数据的移除(同步) wx.clearStorage(Object object)数据的清空(异步) wx.clearStorageSync()数据的清空(同步) 其中,Sync为英文单词synchronization的前4个字母,表示同步,因此API函数中带有Sync后缀的函数为同步函数。同步函数与异步函数之间的区别是,异步不会阻塞当前任务,同步缓存直到同步方法处理完才能继续往下执行。另外,异步函数中含有成功回调函数,可用于数据处理成功后的操作。 这里以wx.login()中使用的wx.setStorage()为例,将wx.request()返回的openid存储于本地,方便openid的获取,使用wx.setStorage()的代码示例如下: wx.setStorageSync('jiaoxue_OPENID', res.data.openid) 编译后,可以在调试器的Storage面板中看到openid已存入本地,Key的值为jiaoxue_OPENID,Value的值为用户的openid,如图33所示。 图33Storage面板中的本地缓存 如果使用wx.setStorage()进行数据存储,可以对数据存储成功后进行操作,代码较wx.setStorageSync()有变化,具体代码如下: wx.setStorage({ key: 'jiaoxue_OPENID', data: res.data.openid, success:function(){ console.log('存储成功') } }) 编译后,同样将openid存储于本地缓存,并执行成功回调函数,Console面板打印出“存储成功”,如图34所示。 图34Console面板中的“存储成功” 需要使用本地缓存中的openid时,可以用wx.getStorageSync('jiaoxue_OPENID')从本地获取openid,并赋值给相应的变量。当然wx.getStorage()也可以,这里不再赘述。 5. wx.showModal() 小程序使用wx.showModal(Object)显示模态对话框,它接收一个对象作为参数,该对象所包含的属性如表34所示。 表34wx.showModal(Object)的Object包含属性 属性类型默认值是否必填说明 titlestring是提示的标题 contentstring是提示的内容 showCancelbooleantrue否是否显示“取消”按钮 cancelTextstring取消否“取消”按钮的文字,最多4个字符 cancelColorstring#000000否“取消”按钮的文字颜色,必须是十六进制格式的颜色字符串 confirmTextstring确定否“确定”按钮的文字,最多 4 个字符 confirmColorstring#576B95否“确定”按钮的文字颜色,必须是十六进制格式的颜色字符串 editablebooleanfalse否是否显示输入框 placeholderTextstring否显示输入框时的提示文本 successfunction否接口调用成功的回调函数 failfunction否接口调用失败的回调函数 completefunction否接口调用结束的回调函数(无论调用成功或失败都会执行) 其中,success()的返回参数详见表35。 表35success()的返回参数 属性类型说明最低版本 contentstringeditable为true时,用户输入的文本 confirmboolean为 true 时,表示用户单击了“确定”按钮 cancelboolean为 true 时,表示用户单击了“取消”按钮(用于Android系统区分单击“蒙层”按钮关闭还是单击“取消”按钮关闭)1.0.0 在进入豆豆云助教时,如果用户没有注册过,会弹出模态弹窗提示用户前往注册,具体代码如下: if (!res.data.is_register) { wx.showModal({ title: '提示', content: '请先注册', showCancel: false, confirmText: "确定", success: function(res) { wx.navigateTo({ url: '/pages/register/userlogin', }) } }) } 编译后,弹出模态对话框,提示用户前往注册,如图35所示。 图35模态对话框提示注册(不含“取消”按钮) 另外尝试在该wx.showModel()的基础上,进行简单的修改,首先将showCancel属性删除,这样模态弹窗会默认showCancel的值为true。然后添加一个成功回调函数success(),通过console.log()查看一下success()的返回值具体有哪些,具体代码如下: wx.showModal({ title: '提示', content: '请先注册', confirmText: "确定", success: function(res) { console.log(res) if(res.confirm){ console.log('"确定"按钮被单击') wx.navigateTo({ url: '/pages/register/userlogin', }) }else if(res.cancel){ console.log('"取消"按钮被点击') } } }) 编译后,效果图如图36所示。在Console面板中可以看到打印出来的success()函数的返回值,如图37所示。 图36模态对话框提示注册(含“取消”按钮) 图37success()函数的返回值 观看视频 3.1.2授权登录页面实现 1. 新建小程序项目 首先新建一个小程序项目,具体操作与1.1.3节中Hello World小程序的新建一样,新建项目时,建议开发者自定义项目名称,并且在存放小程序项目的目录下新建一个空的文件夹,项目目录选择该文件夹,这样方便之后寻找项目所在目录。项目名称可自定义,本书将项目名称命名为doudouyun,与项目相关,具体如图38所示。 图38新建豆豆云(doudouyun)项目 2. 新建userlogin页面 完成项目新建后,需要新建一个授权登录页面,首先右击pages目录,选择“新建文件夹”,并命名为register。然后右击register目录,选择“新建Page”,并命名为userlogin,如图39和图310所示。 选择“新建Page”而不选择一个一个文件新建,原因是选择“新建Page”时,app.json的pages属性中会自动添加新建的页面,开发者不需要再手动添加页面路径了。 3. userlogin页面开发 userlogin页面的功能主要是授权,与Hello World小程序中index页面的功能相似,因此只要将index页面各文件内容复制到userlogin页面对应文件中,再在此基础上进行简单修改就可以了。 图39新建register目录 图310新建userlogin页面 首先是wxml文件,userlogin页面结构主要由view、text与button 3种标签组成,并使用class属性定义对应标签的样式,页面中主要是一个“单击授权登录”按钮,具体代码如下: <!--userlogin.wxml--> <view class="container"> <view class="usermotto"> <text class="user-motto">微信授权</text> </view> <view class="userinfo"> <button wx:if="{{!hasUserInfo && canIUse}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo">单击授权登录</button> </view> </view> 然后是wxss文件,相比于Hello World小程序中index.wxss文件,少了两种样式类型,主要保留了userinfo与usermotto,具体代码如下: /**userlogin.wxss**/ .userinfo { display: flex; flex-direction: column; align-items: center; color:#aaa } .usermotto { margin-top: 150px; } 为了使用户更好地体验,一些小细节也要注意一下,如当用户进入授权登录页面时,页面导航栏的标题文字也相应变为“授权页面”,主要就是在json文件中加上一行代码,具体代码如下: { "navigationBarTitleText": "授权页面" } 最后就是userlogin.js中的相关逻辑代码,userlogin页面的逻辑与Hello World小程序中index页面的逻辑基本一样,只是简单调整了一下,原有的事件处理函数bindViewTap()在授权页面不需要了,直接删了就行。然后在onLoad()函数最后加上一个判断语句,判断当hasUserInfo!=false时,跳转至register页面,即注册页面,具体代码如下: if (this.data.hasUserInfo) { wx.navigateTo({ url: './register', }) } 另外getUserInfo()函数中也相应加上一个页面跳转函数wx.navigateTo(),实现当触发事件处理函数getUserInfo()时,跳转至register页面,具体代码如下: getUserInfo: function (e) { wx.navigateTo({ url: './register', }) app.globalData.userInfo = e.detail.userInfo this.setData({ userInfo: e.detail.userInfo, hasUserInfo: true }) } 图311授权登录页面的效果 这里的app.globalData.userInfo=e.detail.userInfo在新版的微信开发者工具中被删除了,需要重新加上。其作用就是将用户信息赋值给这里的全局变量app.globalData.userInfo。 最后授权登录页面的效果如图311所示。 如果之前已经授权过了,看不到想要的授权页面,可以单击工具栏中间区域的“清缓存”按钮,来清除授权记录。 4. app.js 除了完成userlogin页面的开发外,还需要对app.js文件进行修改,首先是wx.login()方法需要完善,然后才能实现小程序登录功能,最终代码如下: wx.login({ success: res => { //发送 res.code 到后台换取 openid, sessionkey, unionid wx.request({ url:'https://zjgsujiaoxue.applinzi.com/index.php/Api/Weixin/code_to_openidv2', data: { 'code': res.code, 'from': 'wx5ee2da791099a208' }, success: function (res) { console.log(res.data) //将sessionid保存到本地storage wx.setStorageSync('jiaoxue_OPENID', res.data.openid) if (!res.data.is_register) { wx.showModal({ title: '提示', content: '请先注册', showCancel: false, confirmText: "确定", success: function (res) { wx.navigateTo({ url: '/pages/register/userlogin', }) } }) } }, fail: function (res) { console.log('res' + res) } }) } }) 注意,wx.request()的data数组中,from对应的是开发者的appid,因此appid的值需要改成开发者自己的appid。 编译后,发现Console面板会提示错误,如图312所示。 图312提示request中url不在合法域名列表中 解决方法: 单击工具栏右侧区域的“详情”按钮,单击“本地设置”,勾选“不校验合法域名、webview(业务域名)、TLS版本以及HTTPS证书”复选框即可,如图313所示。 图313勾选“不校验合法域名、webview(业务域名)、TLS版本以及HTTPS证书”复选框 勾选“不校验合法域名、webview(业务域名)、TLS版本以及HTTPS证书”复选框后,重新编译一次,发现Console面板提示“该appid未注册”,如图314所示。 图314提示“该appid未注册” 这是为了让所有开发者在学习豆豆云前端开发时,使用提供给所有开发者的云后台,豆豆云开发者为开发者专门写了一个接口,注册后即可使用提供的云后台。因此要使wx.login()方法的wx.request()中的url实现访问后台,需要前往https://zjgsujiaoxue.applinzi.com/index.php/Page/Index/register进行使用注册。调用该接口需要2个参数,即开发者的appid与appsecret,如图315所示。 图315API接口注册 填写appid与appsecret后,单击Submit按钮即可完成API接口注册。API接口注册完成后,重新编译代码即可看到Console面板中wx.request()的返回值,主要包括is_login、is_register和openid,如图316所示。 图316wx.request()的返回值 到这里,用户第一次进入授权登录页面的跳转逻辑已经完成。 3.2注册页面 在userlogin的逻辑中要跳转至注册页面,那就需要新建一个register页面。本节主要先对注册页面中的一些知识点进行讲解,再具体介绍如何完成注册页面的开发。 观看视频 3.2.1注册页面知识点讲解 注册页面主要新增了3个知识点,分别是微信官方UI库WeUI、bindchange事件和openAlert()函数。 1. 微信官方UI库WeUI WeUI是一套同微信原生视觉体验一致的基础样式库,由微信官方设计团队为微信内网页和微信小程序量身设计,令用户的使用感知更加统一,包含button、cell、dialog、progress、toast、article、actionsheet、icon等元素。WeUI基础样式库下载地址为https://github.com/Tencent/weuiwxss。开发者可以将样式库下载并使用微信开发者工具打开dist目录(注意,是dist目录,不是整个项目),导入dist目录后,可以预览样式库,如图317所示。 图317WeUI样式库预览 开发者可以在样式库中选择自己所需要的样式,直接将需要的样式对应的wxml代码复制、粘贴至自己的项目中,然后将WeUI中style文件复制到自己的项目目录中,如将图318所示的目录下style文件夹复制到图319所示的目录下。 图318dist目录下的style文件夹 图319doudouyun项目下的style文件夹 将style文件夹复制到自己开发的项目后,还需要在app.wxss文件中使用@import导入WeUI的样式,如图320所示。到这里,即可正常使用WeUI库中微信的官方样式。 图320导入WeUI样式 2. bindchange事件 bindchange事件与bindtap事件不同,它主要是当输入框中的内容发生改变时,触发对应的事件处理函数,并且输入框中的值可以通过event.detail.value来获取,举个简单的例子,代码如下。 wxml文件代码: <view class="weui-cells weui-cells_after-title"> <view class="weui-cell weui-cell_active"> <view class="weui-cell__hd"> <view class="weui-label">qq</view> </view> <view class="weui-cell__bd"> <input class="weui-input" placeholder-class="weui-input__placeholder" placeholder="请输入qq" bindchange="changevalue"/> </view> </view> </view> js文件代码: Page({ data: { qq:0 }, changevalue:function(event){ console.log(event) this.setData({ qq: event.detail.value }) }, }) 页面效果如图321所示。 图321bindchange使用样例 当在输入框输入内容后,单击其他空白处,可以打印出changevalue()函数的返回值,会发现输入的内容被存放在detail的value中,如图322所示。 图322bindchange事件触发后value的值 3. openAlert()函数 openAlert()函数是在js文件中自定义的一个函数,在定义函数后,可以在其他函数中使用this.openAlert()调用openAlert()函数。 3.2.2注册页面实现 注册页面实现主要分为两部分: 一部分是注册页面的页面布局; 另一部分则是注册页面的功能实现。 观看视频 1. 注册页面的页面布局 与新建userlogin页面一样,在register目录下,右击register,选择“新建Page”,并命名为register。建完register页面后,接下来就是往页面里写内容了。 首先看一下register页面最后的效果,如图323所示。 然后在WeUI基础样式库中找到对应的样式,其中姓名、手机号、学校、学号和入学年份是一个输入框,对应的是WeUI中表单→input里面的一种样式,如图324所示。单击模拟器下方的“打开”按钮,即可在编辑器的目录结构区找到该页面对应的目录,打开input.wxml文件,找到该样式对应的代码,如图325所示。将其复制到doudouyun项目的register.wxml中,其中这段代码最后还少了一个</view>,作为最开始<view>的结束。 图323注册页面效果 图324WeUI样式库中对应的input样式 图325input.wxml中样式对应的代码 以姓名的input为例,其他都与姓名的操作一致,代码如下。 register.wxml代码: <view class="weui-cells weui-cells_after-title"> <view class="weui-cell weui-cell_active"> <view class="weui-cell__hd"> <view class="weui-label">姓名</view> </view> <view class="weui-cell__bd"> <input class="weui-input" placeholder-class="weui-input__placeholder" placeholder="请输入姓名" bindchange="changeName"/> </view> </view> </view> 观看视频 2. 注册页面的功能实现 注册页面的功能实现需要完善register.js中的代码,代码如下: Page({ data: { name: '' }, changeName:function(e){ this.setData({ name: e.detail.value }) } }) 其他注册信息的输入框与姓名一样,分别加入wxml代码,并在data数组中加入对应的变量,对应的bindchange()函数进行修改即可。 除了输入框外,最后还有一个“提交”按钮,在WeUI样式库中的表单→button找到对应的button样式,如图326所示。 图326WeUI样式库中对应的button样式 然后在register.wxml文件的最后加上一段button的代码,具体代码如下: <view class="page__bd submit"> <navigator class="weui-btn weui-btn_primary" aria-role="button" url="javascript:" bindtap="bindSubmit">提交</navigator> </view> 其中,第一个<view>的class类的最后新加一个submit子类,并在wxss文件中写submit子类样式的相关属性,主要是为了调整“提交”按钮的样式。其中,margin后面如果只有两个参数,那么第一个表示top和bottom,第二个表示left和right。margin: 0 auto,表示上下边界为0,左右则根据宽度自适应相同值(即居中)。paddingtop的作用是使button与input之间有一定距离,而不是紧紧连接在一起。并设置width为屏幕宽度的90%。具体代码如下: .submit{ margin: 0 auto; padding-top: 15px; width: 90%; } “提交”按钮绑定的事件处理函数bindSubmit(),主要向后台发送用户注册信息,这里后台提供了一个API接口用于将注册信息存入后台数据库。请求成功后,跳转至index页面,具体代码如下: bindSubmit: function (e) { wx.request({ url: 'http://zjgsujiaoxue.applinzi.com/index.php/Api/User/register_by_openid', data: { openid: wx.getStorageSync('jiaoxue_OPENID'), globalData: JSON.stringify(app.globalData.userInfo), name: this.data.name, tel: this.data.tel, school: this.data.school, num: this.data.num, enter_year: this.data.year }, success: res => { if (res.data.is_register) { wx.redirectTo({ url: '../index/index', }) } }, fail: res => { }, }) }, 3.3“我的”页面 用户在注册页面填入注册信息后,单击“提交”按钮,完成豆豆云的注册。然后跳转至index页面,这里需要新建一个“我的”页面,用于用户查看注册信息,本节主要讲解的就是如何开发“我的”页面。 观看视频 3.3.1“我的”页面知识点讲解 “我的”页面主要新增了两个知识点: 微信小程序媒体组件image的属性和wxss属性的介绍。 1. image组件的属性 image组件的属性详见表36。 表36image组件的属性 属性名类型说明 srcstring图片资源地址 modestring图片裁剪、缩放的模式 binderroreventhandle当错误发生时触发,event.detail = {errMsg} bindloadeventhandle当图片载入完毕时触发,event.detail = {height,width} 注: image组件默认宽度为300px、高度为225px。 图327中image组件用到了三目运算作为判断,三目运算符的定义: <表达式1> ? <表达式2>:<表达式3>; “?”运算符的含义是: 先求表达式1的值,如果为真,则执行表达式2,并返回表达式2的结果; 如果表达式1的值为假,则执行表达式3,并返回表达式3的结果。 图327images组件 试验中的image链接语句: src="{{userInfo.head_img1?userInfo.head_img:'/images/default_head_circle.png'}} 是三目运算符。首先判断storage中是否获取到userInfo.head_img,如图328所示。 图328userinfo中头像信息 如果storage中获取到userInfo.head_img,图片资源地址则为userInfo.head_img,反之则为image文件中的default_head_circle.png图片。 2. wxss属性介绍 rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在iPhone 6中,屏幕宽度为375px,共有750个物理像素,则750rpx=375px=750物理像素,1rpx=0.5px=1物理像素。设备对应的单位换算详见表37。 表37设备对应的单位换算 设备rpx换算px (屏幕宽度/750)px换算rpx (750/屏幕宽度) iPhone 51rpx=0.42px1px=2.34rpx iPhone 61rpx=0.5px1px=2rpx iPhone 6 Plus1rpx=0.552px1px=1.81rpx 建议开发微信小程序时设计师可以用iPhone 6作为视觉稿的标准。 注意,在较小的屏幕上不可避免地会有一些毛刺,请在开发时尽量避免这种情况。 .head_img { height: 120rpx; width: 120rpx; border-radius: 50%; } .weui-cell__ft { color: #000; } height为图片的高度; width为图片的宽度; borderradius为圆角的角度,为图片添加圆角边框,例如borderradius: 50%,就是以百分比定义圆角的形状; color为文字的颜色。 观看视频 3.3.2“我的”页面实现 右击pages,选择“新建文件夹”,命名为my。右击my目录,选择“新建Page”,命名为myinfo。 在app.json中新增tabBar,分别导航到index首页和myinfo“我的”页面,具体操作可参考1.4.2节。 “我的”页面的实现与注册页面差不多,其中“我的”页面效果如图329所示。 首先在WeUI样式库中找到对应的样式,查看WeUI中list样式,发现要找的是“带说明、跳转的列表项”,如图330所示。myinfo.wxml文件中的代码如下。 图329“我的”页面效果 图330WeUI样式库中对应的list样式 <view class="weui-cells weui-cells_after-title"> <navigator url="" class="weui-cell weui-cell_access" hover-class="weui-cell_active"> <view class="weui-cell__bd">头像</view> <view class="weui-cell__ft weui-cell__ft_in-access"> <image class= "head_img" src="{{userinfo.head_img?userinfo.head_img:'/images/default_head_circle.png'}}"> </image> </view> </navigator> <navigator url="" class="weui-cell weui-cell_access" hover-class="weui-cell_active"> <view class="weui-cell__bd">姓名</view> <view class="weui-cell__ft weui-cell__ft_in-access">{{userinfo.name}}</view> </navigator> <navigator url="" class="weui-cell weui-cell_access" hover-class="weui-cell_active"> <view class="weui-cell__bd">手机号</view> <view class="weui-cell__ft weui-cell__ft_in-access">{{userinfo.tel}}</view> </navigator> <navigator url="" class="weui-cell weui-cell_access" hover-class="weui-cell_active"> <view class="weui-cell__bd">性别</view> <view class="weui-cell__ft weui-cell__ft_in-access">{{userinfo.sex}}</view> </navigator> <navigator url="" class="weui-cell weui-cell_access" hover-class="weui-cell_active"> <view class="weui-cell__bd">学校</view> <view class="weui-cell__ft weui-cell__ft_in-access">{{userinfo.school}}</view> </navigator> <navigator url="" class="weui-cell weui-cell_access" hover-class="weui-cell_active"> <view class="weui-cell__bd">学号</view> <view class="weui-cell__ft weui-cell__ft_in-access">{{userinfo.number}}</view> </navigator> <navigator url="" class="weui-cell weui-cell_access" hover-class="weui-cell_active"> <view class="weui-cell__bd">入学年份</view> <view class="weui-cell__ft weui-cell__ft_in-access">{{userinfo.enter_year}}</view> </navigator> </view> 其中,userinfo的值是通过向后台访问请求,获取到的用户信息,并存在本地,然后从本地读取出来进行赋值。 当没有获取到用户信息时,显示默认头像,所以需要在images文件夹下放默认头像图片,这里默认头像的名称为default_head_circle.png,通过userinfo.head_img?userinfo.head_img: '/images/default_head_circle.png'来判断是否获取到了用户头像。 该请求的代码写在app.js中,具体位置如图331所示,具体代码如下: wx.request({ url: 'https://zjgsujiaoxue.applinzi.com/index.php/Api/User/getInfo', data: { 'openid': res.data.openid, }, success: function (res1) { wx.setStorageSync('userInfo', res1.data.data) }, }) 图331访问后台获取用户信息 在myinfo.js文件的data数组中定义变量userinfo,并在onLoad()函数中对userinfo变量进行赋值,具体代码如下: Page({ /** * 页面的初始数据 */ data: { userinfo:{ } }, /** * 生命周期函数--监听页面加载 */ onLoad: function (options) { this.setData({ userinfo: wx.getStorageSync('userInfo') }) } 编译后发现头像显示过大,如图332所示。 图332头像显示过大 因此需要在媒体组件image中自定义类head_img,调整图片大小。其中myinfo.wxss文件的代码如下: .head_img{ height: 120rpx; width: 120rpx; border-radius: 50%; } 到这里,“我的”页面就能正常显示了。 3.4作业思考 一、 讨论题 1. 讨论对小程序登录流程的理解。 2. 如何理解数据缓存中同步与异步缓存的区别? 3. 如何快速找到并使用WeUI基础样式库中自己需要的样式? 4. 样式中margin属性值为 0 auto是什么意思? 5. bindchange与bindtap有什么区别? 6. 新建tabBar之后,register页面中页面跳转的逻辑是否需要修改? 7. 如何修改图片大小和形状? 8. 近年来,网上个人信息泄露事件时有发生,你知道有哪些因网上个人信息泄露造成财产损失的案件? 二、 单选题 1. 在iPhone 6的开发模式中rpx和px的比例是()。 A. 1rpx=2px B. 1rpx=0.5px C. 1rpx=0.552px D. 1rpx=3px 2. wx.login()的属性有()。 A. success、fail、timeout、complete B. success、fail、data、complete C. success、fail、timeout、data D. success、fail、url、data 3. 小程序使用wx.showModal(Object)显示模态弹窗,以下()参数可以用于不显示“取消”按钮。(B) A. confirmText B. showCancel C. content D. cancelText 4. wx.request()中以下()说法是不正确的。 A. url是开发者服务器的接口地址 B. data是请求的参数 C. complete()是调用结束的回调函数(只有调用成功才会执行) D. dataType默认值是json 5. 页面配置的json中()配置导航栏文字内容。 A. navigationBarBackgroundColor B. navigationBarTextStyle C. navigationBarTitleText D. navigationStyle 6. 当wxml的input组件通过bindchange事件绑定了js的changname: function(e)函数,可通过()打印input组件中改变的值。 A. console.log(e.detail.value) B. console.log(e.detail.input) C. console.log(e.value) D. console.log(e.input) 7. 以下关于 image组件的属性()是错误的。 A. src: 图片的资源地址 B. mode: 图片裁剪、缩放的模式 C. binderror: 当没有错误发生时,发布到AppService的事件名,事件对象:event.detail={errMsg:'something wrong'} D. bindload: 当文档载入完毕时,发布到AppService的事件名,事件对象event.detail={height:'图片高度px',width:'图片宽度px'} 8. 关于滚动视图<scrollview>,以下说法不正确的是()。 A. 可以设置scrollx属性进行横向滚动 B. 可以自定义任意角度的滚动方向 C. 可以设置scrolly属性进行纵向滚动 D. 纵向滚动时,必须设置该组件的固定高度 9. 以下代码表示提示框将会出现()。 wx.showToast({ title: '成功', icon: 'success', duration: 2000 }) A. 2000min B. 2000s C. 2000ms D. 200ms 10. 关于borderradius说法正确的是()。 A. 为图片添加边框 B. 为图片添加圆角边框 C. 为文字添加圆角边框 D. 为图片改变边框大小