今天是这个系列教程的最后一篇。
上一篇教程介绍了,小程序页面如何使用 JavaScript 脚本。有了脚本以后,就可以调用微信提供的各种能力(即微信 API),从而做出千变万化的页面。本篇就介绍怎么使用 API。
所有示例的完整代码,都可以从 GitHub 的代码仓库下载。
一、WXML 渲染语法
前面说过,小程序的页面结构使用 WXML 语言进行描述。
WXML 的全称是微信页面标签语言(Weixin Markup Language),它不仅提供了许多功能标签,还有一套自己的语法,可以设置页面渲染的生效条件,以及进行循环处理。
微信 API 提供的数据,就通过 WXML 的渲染语法展现在页面上。比如,home.js
里面的数据源是一个数组。
Page({ data: { items: ['事项 A', '事项 B', '事项 C'] } });
上面代码中,Page()
的参数配置对象的data.items
属性是一个数组。通过数据绑定机制,页面可以读取全局变量items
,拿到这个数组。
拿到数组以后,怎样将每一个数组成员展现在页面上呢?WXML 的数组循环语法,就是一个很简便的方法。
打开home.wxml
,改成下面的代码。
<view> <text class="title" wx:for="{{items}}"> {{index}}、 {{item}} </text> </view>
上面代码中,<text>
标签的wx:for
属性,表示当前标签(<text>
)启用数组循环,处理items
数组。数组有多少个成员,就会生成多少个<text>
。渲染后的页面结构如下。
<view> <text>...</text> <text>...</text> <text>...</text> </view>
在循环体内,当前数组成员的位置序号(从0
开始)绑定变量index
,成员的值绑定变量item
。
开发者工具导入项目代码,页面渲染结果如下。
这个示例的完整代码,可以参考代码仓库。
WXML 的其他渲染语法(主要是条件判断和对象处理),请查看官方文档。
二、客户端数据储存
页面渲染用到的外部数据,如果每次都从服务器或 API 获取,有时可能会比较慢,用户体验不好。
小程序允许将一部分数据保存在客户端(即微信 App)的本地储存里面(其实就是自定义的缓存)。下次需要用到这些数据的时候,就直接从本地读取,这样就大大加快了渲染。本节介绍怎么使用客户端数据储存。
打开home.wxml
,改成下面的代码。
<view> <text class="title" wx:for="{{items}}"> {{index}}、 {{item}} </text> <input placeholder="输入新增事项" bind:input="inputHandler"/> <button bind:tap="buttonHandler">确定</button> </view>
上面代码除了展示数组items
,还新增了一个输入框和一个按钮,用来接受用户的输入。背后的意图是,用户通过输入框,为items
数组加入新成员。
开发者工具导入项目代码,页面渲染结果如下。
注意,输入框有一个input
事件的监听函数inputHandler
(输入内容改变时触发),按钮有一个tap
事件的监听函数buttonHandler
(点击按钮时触发)。这两个监听函数负责处理用户的输入。
然后,打开home.js
,代码修改如下。
Page({ data: { items: [], inputValue: '' }, inputHandler(event) { this.setData({ inputValue: event.detail.value || '' }); }, buttonHandler(event) { const newItem = this.data.inputValue.trim(); if (!newItem) return; const itemArr = [...this.data.items, newItem]; wx.setStorageSync('items', itemArr); this.setData({ items: itemArr }); }, onLoad() { const itemArr = wx.getStorageSync('items') || []; this.setData({ items: itemArr }); } });
上面代码中,输入框监听函数inputHandler()
只做了一件事,就是每当用户的输入发生变化时,先从事件对象event
的detail.value
属性上拿到输入的内容,然后将其写入全局变量inputValue
。如果用户删除了输入框里面的内容,inputValue
就设为空字符串。
按钮监听函数buttonHandler()
是每当用户点击提交按钮,就会执行。它先从inputValue
拿到用户输入的内容,确定非空以后,就将其加入items
数组。然后,使用微信提供的wx.setStorageSync()
方法,将items
数组存储在客户端。最后使用this.setData()
方法更新一下全局变量items
,进而触发页面的重新渲染。
wx.setStorageSync()
方法属于小程序的客户端数据储存 API,用于将数据写入客户端储存。它接受两个参数,分别是键名和键值。与之配套的,还有一个wx.getStorageSync()
方法,用于读取客户端储存的数据。它只有一个参数,就是键名。这两个方法都是同步的,小程序也提供异步版本,请参考官方文档。
最后,上面代码中,Page()
的参数配置对象还有一个onLoad()
方法。该方法属于页面的生命周期方法,页面加载后会自动执行该方法。它只执行一次,用于页面初始化,这里的意图是每次用户打开页面,都通过wx.getStorageSync()
方法,从客户端取出以前存储的数据,显示在页面上。
这个示例的完整代码,可以参考代码仓库。
必须牢记的是,客户端储存是不可靠的,随时可能消失(比如用户清理缓存)。用户换了一台手机,或者本机重装微信,原来的数据就丢失了。所以,它只适合保存一些不重要的临时数据,最常见的用途一般就是作为缓存,加快页面显示。
三、远程数据请求
小程序可以从外部服务器读取数据,也可以向服务器发送数据。本节就来看看怎么使用小程序的网络能力。
微信规定,只有后台登记过的服务器域名,才可以进行通信。不过,开发者工具允许开发时放松这个限制。
按照上图,点击开发者工具右上角的三条横线("详情"),选中"不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书" 。这样的话,小程序在开发时,就可以跟服务器进行通信了。
下面,我们在本地启动一个开发服务器。为了简单起见,我选用了 json-server 作为本地服务器,它的好处是只要有一个 JSON 数据文件,就能自动生成 RESTful 接口。
首先,新建一个数据文件db.json
,内容如下。
{ "items": ["事项 A", "事项 B", "事项 C"] }
然后,确认本机安装了 Node.js 以后,进入db.json
所在的目录,在命令行执行下面命令,启动服务器。
npx json-server db.json
正常情况下,这时你打开浏览器访问localhost:3000/items
这个网址,就能看到返回了一个数组["事项 A", "事项 B", "事项 C"]
。
接着,打开home.js
,代码修改如下。
Page({ data: { items: [] }, onLoad() { const that = this; wx.request({ url: 'http://localhost:3000/items', success(res) { that.setData({ items: res.data }); } }); } });
上面代码中,生命周期方法onLoad()
会在页面加载后自动执行,这时就会执行wx.request()
方法去请求远程数据。如果请求成功,就会执行回调函数succcess()
,更新页面全局变量items
,从而让远程数据显示在页面上。
wx.request()
方法就是小程序的网络请求 API,通过它可以发送 HTTP 请求。它的参数配置对象最少需要指定url
属性(请求的网址)和succcess()
方法(服务器返回数据的处理函数)。其他参数请参考官方文档。
开发者工具导入项目代码,页面渲染结果如下。它的初始数据是从服务器拿到的。
这个示例的完整代码,可以参考代码仓库。
这个例子只实现了远程数据获取,json-server 实际上还支持数据的新增和删改,大家可以作为练习,自己来实现。
四、<open-data>
组件
如果要在页面上展示当前用户的身份信息,可以使用小程序提供的<open-data>
组件。
打开home.wxml
文件,代码修改如下。
<view> <open-data type="userAvatarUrl"></open-data> <open-data type="userNickName"></open-data> </view>
上面代码中,<open-data>
组件的type
属性指定所要展示的信息类型,userAvatarUrl
表示展示用户头像,userNickName
表示用户昵称。
开发者工具导入项目代码,页面渲染结果如下,显示你的头像和用户昵称。
<open-data>
支持的用户信息如下。
userNickName
:用户昵称userAvatarUrl
:用户头像userGender
:用户性别userCity
:用户所在城市userProvince
:用户所在省份userCountry
:用户所在国家userLanguage
:用户的语言
这个示例的完整代码,可以参考代码仓库。
<open-data>
不需要用户授权,也不需要登录,所以用起来很方便。但也是因为这个原因,小程序不允许用户脚本读取<open-data>
返回的信息。
五、获取用户个人信息
如果想拿到用户的个人信息,必须得到授权。官方建议,通过按钮方式获取授权。
打开home.wxml
文件,代码修改如下。
<view> <text class="title">hello {{name}}</text> <button open-type="getUserInfo" bind:getuserinfo="buttonHandler"> 授权获取用户个人信息 </button> </view>
上面代码中,<button>
标签的open-type
属性,指定按钮用于获取用户信息,bind:getuserinfo
属性表示点击按钮会触发getuserinfo
事件,即跳出对话框,询问用户是否同意授权。
用户点击"允许",脚本就可以得到用户信息。
home.js
文件的脚本代码如下。
Page({ data: { name: '' }, buttonHandler(event) { if (!event.detail.userInfo) return; this.setData({ name: event.detail.userInfo.nickName }); } });
上面代码中,buttonHandler()
是按钮点击的监听函数,不管用户点击"拒绝"或"允许",都会执行这个函数。我们可以通过事件对象event
有没有detail.userInfo
属性,来判断用户点击了哪个按钮。如果能拿到event.detail.userInfo
属性,就表示用户允许读取个人信息。这个属性是一个对象,里面就是各种用户信息,比如头像、昵称等等。
这个示例的完整代码,可以参考代码仓库。
实际开发中,可以先用wx.getSetting()
方法判断一下,用户是否已经授权过。如果已经授权过,就不用再次请求授权,而是直接用wx.getUserInfo()
方法获取用户信息。
注意,这种方法返回的用户信息之中,不包括能够真正识别唯一用户的openid
属性。这个属性需要用到保密的小程序密钥去请求,所以不能放在前端获取,而要放在后端。这里就不涉及了。
六、多页面的跳转
真正的小程序不会只有一个页面,而是多个页面,所以必须能在页面之间实现跳转。
app.json
配置文件的pages
属性就用来指定小程序有多少个页面。
{ "pages": [ "pages/home/home", "pages/second/second" ], "window": ... }
上面代码中,pages
数组包含两个页面。以后每新增一个页面,都必须把页面路径写在pages
数组里面,否则就是无效页面。排在第一位的页面,就是小程序打开时,默认展示的页面。
新建第二个页面的步骤如下。
第一步,新建pages/second
目录。
第二步,在该目录里面,新建文件second.js
,代码如下。
Page({});
第三步,新建第二页的页面文件second.wxml
,代码如下。
<view> <text class="title">这是第二页</text> <navigator url="../home/home">前往首页</navigator> </view>
上面代码中,<navigator>
就是链接标签,相当于网页标签<a>
,只要用户点击就可以跳转到url
属性指定的页面(这里是第一页的位置)。
第四步,修改第一页的页面文件home.wxml
,让用户能够点击进入第二页。
<view> <text class="title">这是首页</text> <navigator url="../second/second">前往第二页</navigator> </view>
开发者工具导入项目代码,页面渲染结果如下。
用户点击"前往第二页",就会看到第二个页面。
这个示例的完整代码,可以参考代码仓库。
七、wx.navigateTo()
除了使用<navigator>
组件进行页面跳转,小程序也提供了页面跳转的脚本方法wx.navigateTo()
。
首先,打开home.wxml
文件,代码修改如下。
<view> <text class="title">这是首页</text> <button bind:tap="buttonHandler">前往第二页</button> </view>
开发者工具导入项目代码,页面渲染结果如下。
然后,打开home.js
文件,代码修改如下。
Page({ buttonHandler(event) { wx.navigateTo({ url: '../second/second' }); } });
上面代码中,buttonHandler()
是按钮点击的监听函数,只要用户点击按钮,就会调用wx.navigateTo()
方法。该方法的参数是一个配置对象,该对象的url
属性指定了跳转目标的位置,自动跳转到那个页面。
这个示例的完整代码,可以参考代码仓库。
写到这里,这个小程序入门教程就告一段落了,入门知识基本上都涉及了。下一步,大家可以阅读小程序的官方教程和使用文档,争取对小程序 API 有一个整体的把握,然后再去看看各种实际项目的源码,应该就可以动手开发了。以后,我还会写小程序的进阶教程,包括云开发,介绍如何写小程序的后端,下次再见。
(完)
小鱼果 说:
感谢阮老师分享,最近正想研究研究小程序呢。
2020年11月 2日 22:13 | # | 引用
节点 说:
获取用户个人信息示例部分,无论模拟器还是真机,都没有弹窗提示“微信授权”的窗口呢 Orz 而是直接获取了我的微信名称并加载到页面里了。
感谢软老师的教程带我入门,完结撒花
2020年11月 3日 11:28 | # | 引用
rainbow 说:
哈哈哈,更新及时、谢谢大哥
2020年11月 3日 11:52 | # | 引用
飞扬 说:
又有想法去学习开发小程序了,之前没有好的教程,做到一半。。
2020年11月 3日 11:58 | # | 引用
黄笑 说:
bind:input 应该没有冒号吧
2020年11月 3日 18:13 | # | 引用
黄笑 说:
试了高阶的版本是可以的,是我弄错了。。
2020年11月 3日 18:21 | # | 引用
codeniu 说:
高阶版本是啥意思。
2020年11月 4日 20:14 | # | 引用
a 说:
@ 节点 你是用的wxml tag 没用js读取吧?
2020年11月 5日 07:18 | # | 引用
PGambler 说:
感谢,阮老师分享,学习中!
2020年11月 5日 10:16 | # | 引用
丨追灬寻 说:
阮大来一波k8s教程吧
2020年11月 5日 14:28 | # | 引用
elon 说:
已学习完,感谢大佬优质分享
2020年11月10日 18:21 | # | 引用
shaynelee 说:
期待进阶高级教程
2020年11月10日 22:31 | # | 引用
creamaa 说:
大牛就是大牛
期待进阶版本
2020年11月15日 19:46 | # | 引用
萌新 说:
受益匪浅
2020年11月19日 09:49 | # | 引用
netwjx 说:
homer好评 ^_^
2020年11月19日 15:59 | # | 引用
忆零 说:
简洁易懂,期待高阶教程!
2020年11月23日 21:17 | # | 引用
Shing 说:
感谢,期待后续的小程序进阶教程。
2020年11月24日 15:18 | # | 引用
xiaoniu 说:
期待后续
2020年11月27日 20:06 | # | 引用
somenzz 说:
示例代码中inputHandler没有被触发,不知道怎么回事,请教高手回答一下
2020年12月 1日 10:13 | # | 引用
初学者 说:
<navigator url="../playing/playing">前往首页</navigator>
跳转界面 没效果 会是什么原因呢? 没报错 没提示 没作为 就是静默
通过按钮调用方法跳转也不能实现页面跳转效果, 这里确实有报错,说是:
VM23 WAService.js:2 (in promise) MiniProgramError
{"errMsg":"navigateTo:fail can not navigateTo a tabbar page"}
Object
网上说的解决方案,没看懂 ,也没改善效果
2020年12月 1日 19:21 | # | 引用
andy 说:
const itemArr = [...this.data.items, newItem];
没看懂等号右边的部分。哪位大侠解释下?
2020年12月 2日 15:48 | # | 引用
xilin 说:
期待以后的文章,这四篇挺简单
2020年12月 3日 13:31 | # | 引用
BecomeBamboo 说:
感谢阮老师浅显易懂的教程,文笔朴实生动通俗易懂,撸一遍代码受益匪浅,感谢!
2020年12月 3日 16:45 | # | 引用
飘逸星辰YY 说:
@初学者:
这是因为你把playing页面在app.json里设置成了tabBar页面,navigateTo不能跳转到tabBar页面
2020年12月 4日 17:09 | # | 引用
Can 说:
就是 Vue和React的合体啊, 各取千秋, 加上微信支付和获取用户信息这关键的API
2020年12月 4日 22:54 | # | 引用
qszy 说:
感谢分享, 看到阮大的分享, 总认为是最合适的.能够让人看懂理解的内容.
2020年12月 7日 13:32 | # | 引用
Jimmy 说:
感谢分享,写的真好,期待阮老师的下一步哈。
2020年12月10日 11:09 | # | 引用
诗和远方在明天 说:
简明扼要、思路清晰!
2020年12月17日 16:16 | # | 引用
大高贵 说:
期待高阶~关注大佬很久啦~
2020年12月17日 17:32 | # | 引用
姜二 说:
这是js的语法,等号右边的中括号,表示要重新定义一个数组。中括号内,就放一个个的数组元素。 ...(三个点) 代表展开数组,可以简单理解为把this.data.items中的每个元素,复制到中括号里了,然后再新加了一个 newItem元素,最终的目的是把this.data.items追加一个新元素,再返回给itemArr。
2020年12月20日 14:23 | # | 引用
小赵 说:
期待后续更新
2020年12月23日 16:14 | # | 引用
ljx 说:
解决一:bindinput (不要冒号)
解决二:在右上角【详情】-》【本地设置】中,把【调试基础库】版本选高点。
2021年1月 6日 22:02 | # | 引用
流光 说:
tabBar 已定义的页面,通过这2种方式均无法跳转
2021年1月 8日 11:31 | # | 引用
topwang 说:
期待高级教程以及云开发、小程序后端
2021年1月12日 15:57 | # | 引用
单车 说:
授权获取用户个人信息
或者是:
授权获取用户个人信息
或者是调整详情-》本地设置-》调试基础库 的版本
或者是重启微信开发者工具
都没有弹出框。。有谁知道原因吗?
2021年2月 7日 20:22 | # | 引用
just 说:
这是 ES6 数组的拓展语法,...this.data.items 表示将 this.data.items 数组里面的元素展开,后面再加上 newItem 组合成一个新的数组
2021年2月21日 22:42 | # | 引用
梦入烟城 说:
谢谢 大神教导,我感觉我会一些简单的小程序编写了!!!
2021年4月 8日 14:38 | # | 引用
Xullnn 说:
感谢这篇教程: )
反馈一下第五部分获取用户信息,新的微信开发工具做出了一些调整。后续的开发不再支持`getUserInfo`, 使用新的`getUserProfile`. 文档地址:
https://developers.weixin.qq.com/community/develop/doc/000cacfa20ce88df04cb468bc52801?idescene=6
自己试了试新接口可以用:
WXML:
```html
<view>
<text class="title"> Hello {{name}}</text>
<button bindtap="getUserProfile">
授权信息
</button>
</view>
```
home.js 部分
```js
getUserProfile(e) {
wx.getUserProfile({
desc: 'test feature',
success: (res) => {
this.setData({
name: res.userInfo.nickName
})
},
fail: (reason) => {
console.log(reason.errMsg)
}
})
}
```
授权确认弹窗会从页面底部弹起,UI也有小的变化。 但自己的尝试都是根据老师前面教程的逻辑来的, 先在home.js中声明好能在view中读取的变量,然后在view中绑定handler, 然后再回到home.js中定义对应的handler, 在这个过程中不断查阅官方doc. 学到很多,再次感谢。
2021年5月 3日 10:34 | # | 引用
halo 说:
json-server 数据的新增和删改 要怎么实现
2021年5月11日 16:30 | # | 引用
呆大王 说:
小程序如如何与mysql服务器做CRUD?
2021年10月18日 10:42 | # | 引用
gaspar 说:
"按钮监听函数buttonHandler()是每当用户点击提交按钮,就会执行。它先从inputValue拿到用户输入的内容,确定非空以后,就将其加入items数组。然后,使用微信提供的wx.setStorageSync()方法,将items数组存储在客户端。最后使用this.setData()方法更新一下全局变量items,进而触发页面的重新渲染。" 这里的 items 应该为 itemArr
2021年10月25日 21:26 | # | 引用
剑行涧远 说:
我也是同样的问题,但是获取不到我的微信名称,而是显示“微信用户”四个字
2022年3月30日 17:27 | # | 引用
松树 说:
初学小程序 通过四个教程很快掌握小程序的基本功能!!!
希望作者还能出后续进阶
2023年1月30日 13:42 | # | 引用
超级快印 说:
看了下开发文档现在用新的的获取方式了
2023年2月 9日 16:27 | # | 引用