微信小程序开发手册
WXML模板
语法
区分大小写。标签必须有开标签和闭标签。
标签
常用标签
- view:相当于html中的div标签,用户页面布局、分块。
- template:模板,在模板中定义代码片段。使用name属性定义、命名模板。使用is属性引用模板。
- import:导入其他wxml文件。src属性指定目标wxml文件。导入目标wxml文件,可直接使用目标文件中的template模板。
- include:引入其他wxml文件。会引入除template、wxs外的所有代码,将代码拷贝到include标签下。
- text:渲染文本,类似与span
标签的共同属性
所有标签都支出的属性称为共同属性,有如下共同属性:
- id:组件的唯一标识
- class:组件的样式类
- style:组件的内联样式
- hidden:组件是否显示
data-*:组件触发事件时,会发送给事件处理函数的数据。事件处理函数通过e.target.dataset.*的方式获取参数。bind*/catch*:监听组件触发的事件,绑定事件处理函数。
与javascript交互
:插值表达式,将js中定义的data绑定到wxml模板上。:插值表达式,可以进行一些简单的逻辑运行。wx:if="condition":逻辑判断语法。为true时,显示标签。为false时,不显示标签。wx:for="":for循环遍历数组渲染标签。wx:for-index="idx":指定数组当前下标的变量名。wx:for-item="itemName":指定数组当前元素的变量名
model:value="":属性双向绑定。
双向绑定
使用model:value=""实现组件属性与js值的双向绑定。
<view style="border:solid 1px black;border-radius: 2%;">
<text>双向绑定</text>
<input style="display: inline;" id="input1" type="text" model:value="{{name}}" />
<text>名称为:{{name}}</text>
<button id="reset" type="primary" bind:tap="tapReset">重置</button>
</view>Page({
data: {
name: "Evan Chen"
},
tapReset: function (event) {
this.setData({
name: "Evan Chen"
});
}WXSS样式表
wxss用于描述wxml的样式,类似于css。相比于css,其拓展了两个特性:
- 尺寸单位
- 样式导入
尺寸单位
wxss提供了rpx的单位,其可以根据屏幕宽度进行自适应,其规定屏幕宽度固定为750rpx。1rpx代表的元素大小,根据实际设备屏幕宽度而调整。
开发中一般会选用iphone6作为显示参考,因为其屏幕宽度为375px,刚好可整除,1px=2rpx。
样式表分类
小程序样式表分为:全局样式、页面样式、其他样式。
- 全局样式定义在app.wxss下
- 页面样式定义在页面目录下的同名.wxss下
- 其他样式定义在自定义目录下,可以通过
@import './test.wxss;'方式在页面中引用其他样式,使用相对路径。
WXSS选择器
WXSS只支持部分的选择器,包括:
- 类选择器:
.class - id选择器:
#id - 元素选择器:
view - 伪类选择器:
button:hover
权重如下:
!important:无限大- 内联样式:1000
- id选择器:100
- 类选择器:10
- 元素选择器:1
组件样式
在框架组件中,使用class、style属性定义样式。
一般情况下,在class属性中定义静态样式,在style中定义动态样式。
<view style="color:{{color}};" />
<view class="normal_view" />WXS脚本段
wxs相当于html的内联脚本,可以通过wxs编写简单的wxs事件响应函数或数据处理逻辑。
其通过导出的方式,将js脚本的属性、函数导出。
<wxs module="m1">
var msg="hello world";
module.export.msg=msg;
</wxs>
<view>{{m1.msg}}</view>
<!-- 渲染除hello world -->在wxs中响应事件
wxs响应事件函数与wxss有所不同,wxs的事件函数接收两个参数,一个是event,一个是ownerInstance。
<wxs module="wxs" src="/pages/index/index.wxs"></wxs>
<button id="button13" type="primary" bind:tap="{{wxs.tapButton13}}">调用wxs</button>//wxs
function tapButton13(event, ownerInstance) {
console.log("event:event", JSON.stringify(event));
console.log("ownerInstance:", JSON.stringify(ownerInstance));
}
module.exports = {
tapButton13: tapButton13
}因为小程序时运行在两个线程下的,一个负责渲染视图,一个负责逻辑处理,所以在需要用户频繁交互的页面上会出现明显卡顿的情况。
比如拖动一个元素A,元素B跟随移动的场景。这时会涉及两个线程的通讯。
因为wxs运行在视图层的线程下,所以比较适合这种场景下使用。即使wxs的功能没有那么丰富,但对于动画切换、动态设置样式的场景是没有问题的。比如给节点的class赋予动态的class属性。
CSS动画
小程序中提供了接口实现开启关键帧动画,格式如下:
//基础动画
this.animate(selector, keyframes, duration, callback)
//滚动驱动的动画
this.animate(selector, keyframes, duration, ScrollTimeline)- selector:节点选择器
- keyframes:关键帧信息。每一帧的css样式。
- duration:动画持续时间,以毫秒为单位
- callback:动画完成后的回调函数
动画监听函数
- bindtransitionend:CSS 渐变结束或
wx.createAnimation结束一个阶段 - bindanimationstart:CSS动画开始时
- bindanimationiteration:CSS动画结束一个阶段
- bindanimationend:CSS动画结束
小程序
每个小程序都需要在app.js中调用APP方法注册小程序实例,在初始化过程中绑定声明周期回调函数、错误监听回调函数。
生命周期函数
- onLaunch:初次打开小程序时触发,只执行一次。
- onShow:小程序状态从后台切换到前台时执行。
- onHide:小程序状态从前台切换到后台时执行。
获取小程序实例
每个小程序只有一个App实例,是全局共享的,可以在Page中调用getApp()获取实例。
const app=getApp();
console.log(app.globalData);//打印globalData数据配置
- initialRenderingCache:静态渲染缓存。在小程序第一次打开后自动生成静态渲染缓存,将会把data中的数据缓存下来,提高下次启动小程序的速度。
页面
Page页面通过在js文件使用Page()函数注册,用于构建简单的页面,初始化过程会绑定页面的生命周期回调函数。
在js中通过getCurrentPage()函数可以获取当前页面栈。
生命周期函数
- onLoad:页面加载时执行
- onShow:页面显示时执行
- onReady:页面初次渲染完成时执行,只会执行一次。
- onHide:页面隐藏时执行
- onUnload:页面卸载时执行
- onPullDownRefresh:用户执行下拉动作时执行
- onReachBottom:页面上拉触底时处理
- onShareAppMessage:用户点击右上角分享时执行
- onPageScroll:页面滚动时执行
下拉刷新
微信小程序提供了下拉刷新功能。在page.json配置文件中设置开启。
{
"enablePullDownRefresh": true
}在page.js中,添加onPullDownRefresh回调函数,绑定下拉刷新事件。
Page({
onPullDownRefresh: function () {
// 用户触发了下拉刷新操作
// 拉取新数据重新渲染界面
console.log("onPullDownRefresh");
wx.stopPullDownRefresh() // 可以停止当前页面的下拉刷新。
},
})上拉触底
微信小程序提供了上拉触底的功能。这个功能用在列表滚动到底部时加载下一页使用。
开启上拉触底需要在page.json配置文件中设置开启。
// 界面的下方距离页面底部距离小于onReachBottomDistance像素时触发onReachBottom回调
{"onReachBottomDistance": 100 }在page.js中,添加onReachBottom回调函数,绑定上拉触底事件。
onReachBottom: function (event) {
// 当界面的下方距离页面底部距离小于100像素时触发回调
console.log("onReachBottom");
}Toast提醒
tapButton2: function (event) {
wx.showToast({
title: '这是一个toast',
duration: 2000,
icon: "success",
mask: true
})
},模态框
tapButton3: function (event) {
wx.showModal({
title: '标题',
content: '这是一个模态框',
complete: (res) => {
if (res.cancel) {
console.log("cancel")
}
if (res.confirm) {
console.log("confirm");
}
}
})
},加载框
tapButton5: function (event) {
wx.showLoading({
title: 'title',
mask: true,
success: (res) => {},
fail: (res) => {},
complete: (res) => {},
})
setTimeout(() => {
wx.hideLoading()
}, 2000);
},组件
组件通过Comonent()函数创建,用于构建复杂的页面。
创建components文件夹,将自定义组件放到该目录下。每个自定义组件再新建一个文件夹存放。
自定义组件同样需要包含.js、.json、.wxml、.wxss文件。
在Page中引用组件
组件的引用方式有两种:
- 局部引用:局部引用是指只能在当前页面内使用。
- 全局引用:全局引用是指可以在小程序全局内使用。
局部引用
使用局部引用的方式引用组件,可以在页面的.json配置文件中添加组件声明,usingComponents配置项。
{
"usingComponents":{
"myComponent":"/components/myComponent/myComponent"
}
}之后在wxml中即可直接使用组件:
<my-component></my-component>全局引用
使用全局引用的方式引用组件,需要在小程序的配置文件app.json中添加组件声明,usingComponents配置项。
{
"usingComponents":{
"myComponent":"/components/myComponent/myComponent"
}
}之后就可以在任意页面使用组件。
组件和页面的区别
- 组件的.json文件中需要声明
"component":true属性,页面中没有。 - 组件的.js文件中调用的是Component()函数,页面调用的是Page()函数。
- 组件的事件处理函数需要定义到methods节点中,页面的处理函数可以定义到与data平级的路径。
组件样式隔离
- 组件A的样式不会影响组件B的样式
- 组件A的样式不会影响小程序页面的样式
- 小程序的页面样式不会影响组件的样式,仅class选择器有组件样式隔离
组件样式隔离策略可以在组件.js文件或组件.json文件中修改styleIsolation选项,可选值:
- isolated:默认值,表示样式隔离。
- apply-shared:页面或全局的样式可以影响到组件,组件的样式不能影响页面或全局的样式。
- shared:没有隔离,页面或全局的样式和组件的样式可以互相影响。
数据监听器
通过observers选项定义数据监听器。
Component({
observers:{
'字段A、字段B':function(字段A的新值,字段B的新值){
//do something
}
}
})纯数据字段
纯数据字段指的是那些不用于界面渲染的data字段,这些字段既不会展示在界面上,也不会传递给其他组件,使用纯数据字段有助于提升页面更新的性能。
Component({
options:{
//指定所有_开头的数据字段为纯数据字段
pureDataPattern:/^_/
}.
data:{
a:true, //普通数据字段
_b:true, //纯数据字段
}
})组件的非事件函数,建议以
_开头定义。
组件的生命周期
- created:在组件实例刚刚被创建时执行
- attached:在组件实例进入页面节点树时执行
- ready:在组件在视图层布局完成后执行
- moved:在组件实例被移动到节点树另一个位置时执行
- detached:在组件实列从页面的节点树移除时执行
- error:当组件的方法抛出错误时执行
组件生命周期函数定义在lifetimes节点。
Component({
lifetimes:{
created(){
console.log("component created")
},
attached(){
console.log("component attached")
}
}
})组件所在页面的生命周期
- show:组件所在页面被展示时执行
- hide:组件所在页面被隐藏时执行
- resize:组件所在的页面尺寸变化时执行
组件所在页面的生命周期函数定义在pageLifetimes节点中
Component({
pageLifetimes:{
show(){
console.log("component show")
},
hide(){
console.log("component hide")
},
resize(size){
console.log("component resize")
}
}
})组件的插槽
组件中通过<slot>标签定义插槽,用于接收组件使用者提供的wxml结构。
<view>view1</view>
<slot>我是插槽</slot>
<view>view2</view>多插槽支持
组件默认只支持定义一个插槽。如需使用多个插槽,可以在组件的.js文件中将options.multipleSlots选项设置为true。
Component({
options:{
//启用组件的多插槽支持
multipleSlots:true
}
})使用多个插槽时,使用插槽的name属性进行区分
<!-- 组件MyComponent -->
<view>view1</view>
<slot name="slot1">我是插槽1</slot>
<slot name="slot2">我是插槽2</slot>
<view>view2</view>
<!-- 页面 -->
<MyComponent>
<view slot="slot1">插槽1的内容</view>
<view slot="slot2">插槽2的内容</view>
</MyComponent>父子组件之间的通信
父子组件间通信有三种方式:
- 父组件设置子组件的属性,实现父组件向子组件通信。
- 父组件绑定子组件的事件,实现子组件向父组件通信。
- 父组件使用
this.selectComponent("id或class选择器")获取子组件的实例对象,实现对子组件的数据、方法的直接访问。
事件通信
事件通信需要父子组件配合完成。
- 子组件中需定义触发事件的逻辑。通过
this.triggerEvent('eventName',{参数对象})方法触发事件。
helloEvent: function() {
this.triggerEvent('hello', {}, {
bubbles: true, // 这是一个冒泡事件
composed: true, // 这个事件在Composed Tree 上冒泡
capturePhase: false // 这个事件没有捕获阶段
})
}- 父组件中定义事件的触发方法、监听事件、绑定事件处理方法。
function triggerMethod(e){
console.log('参数对象为:',e.detail)
}<MyComponent bind:eventName=triggerMethod></MyComponent>获取组件实例
const child=this.selectComponent("id或class选择器")
console.log(child.properties.name) //获取并打印子组件的name属性
child.changeName() //调用子组件的changeName方法behaviors代码共享
behavior是一组数据、属性、方法的集合,behavior可以提供给页面、组件、behavior使用。当behavior被引用时,定义在behavior的内容将会合并到引用它的对象内。behavior主要是用于复用代码。
定义behavior
通过Behavior()函数创建一个behavior,然后导出。
module.exports=Behavior({
data:{
},
property:{
},
method:{
}
})引用behavior
通过require()函数引入behavior
const myBehavior=require("behavior的路径")
Component({
//将导入的behavior实列对象,挂载到behaviors数组节点,即可使用。
behaviors:[myBehavior],
})Behavior可用的节点
- properties:属性
- data:数据
- methods:方法
- behaviors:引用其他behavor
- created:生命周期函数
- attached:生命周期函数
- ready:生命周期函数
- moved:生命周期函数
- detached:生命周期函数
同名字段的覆盖和组合规则
一般规则:组件>behavior
详细规则,看微信小程序官方文档
常用组件
- view
- text
- button
- image
- scroll-view
- rich-text
原生组件
原生组件是指由微信客户端渲染而不是webview渲染的组件。
常见的原生组件有:
- video:视频
- map:地图
- canvas:画布
- picker:弹出式选择器
对于原生组件都会提供context,用于在js代码中操作组件。
事件
事件分类
常见的事件类型有:
| 类型 | 触发条件 |
|---|---|
| touchstart | 手指触摸动作开始 |
| touchmove | 手指触摸后移动 |
| touchcancel | 手指触摸动作被打断,如来电提醒,弹窗 |
| touchend | 手指触摸动作结束 |
| tap | 手指触摸后马上离开 |
| longpress | 手指触摸后,超过350ms再离开,如果指定了事件回调函数并触发了这个事件,tap事件将不被触发 |
| longtap | 手指触摸后,超过350ms再离开(推荐使用longpress事件代替) |
| transitionend | 会在 WXSS transition 或 wx.createAnimation 动画结束后触发 |
| animationstart | 会在一个 WXSS animation 动画开始时触发 |
| animationiteration | 会在一个 WXSS animation 一次迭代结束时触发 |
| animationend | 会在一个 WXSS animation 动画完成时触发 |
组件绑定事件
小程序的组件通过bind、catch绑定事件。
<view bind:tap="handleTap">
<view catch:tap="handleTap">
<view capture-bind:tap="handleTap">
<view capture-catch:tap="handleTap">Page({
handleTap:function(event){
console.log(event);
}
})bind与catch的区别是:bind不会阻止事件传递,而catch会阻止传递。
事件捕获与事件冒泡
wxml中的事件机制与html类似,分为两个阶段:事件捕获、事件冒泡。
事件捕获是事件从上往下传递到组件,事件冒泡是事件从下往上传递到组件。 
通过capture-bind可实现在事件捕获阶段绑定事件处理函数。
<view capture-bind:tap="handleTap">
<view capture-catch:tap="handleTap">不加capture时,即bind可实现在事件冒泡阶段绑定事件处理函数。
事件对象
当组件触发事件时,逻辑层绑定该事件的处理函数会收到一个事件对象。其包含以下属性:
BaseEvent基础事件类型
- type:事件类型
- timeStamp:事件生成的时间戳
- target:触发事件的源组件
- currentTarget:事件函数绑定的当前组件。
- mark:事件标记数据
TouchEvent 触摸事件对象属性列表(继承 BaseEvent):
- touches:当前停留在屏幕中的触摸点信息的数组
- changedTouches:当前变化的触摸点信息的数组
事件参数
在组件中通过date-*的形式传递参数到事件函数,事件函数通过event.currentTarget.dataset.*获取参数。
<button id="button14" type="default" data-first-name="Evan" data-last-name="Chen" bind:tap="tapButton14">事件传递参数</button> tapButton14: function (event) {
console.log(event.currentTarget.dataset.firstName + "." + event.currentTarget.dataset.lastName);
}mark
当事件触发时,事件冒泡路径上所有的mark会被合并。
mark有以下特性:
- 当出现重名时,父节点的mark会覆盖子节点的mark。
- 在自定义组件中接收事件时,mark不包含自定义组件外的mark。
- 不同于dataset,节点的mark不会做连字符和大小写转换。
<view mark:firstName="Evan">
<button id="button15" type="primary" mark:lastName="Chen" bind:tap="tapButton15">事件mask</button>
</view> tapButton15: function (event) {
console.log(event.mark.firstName + "." + event.mark.lastName);
}路由
小程序提供了组件式导航及编程式导航两个路由方式,页面跳转的方式有以下两种:
- 在页面中通过
<navigator>实现。 - 在js中通过
ws.navigateTo、wx.navigateBack、wx.redirectTo、Router.navigateTo等api实现。
路由是由栈维护,路由操作实际上是对栈进行操作。
路由类型
小程序目前有以下7种路由类型:
1.小程序启动:opentype:appLaunch
当小程序启动时,触发appLaunch事件。
2.打开新页面:opentype:navigateTo
打开一个新页面并将其推入路由栈。
可通过wx.navigateTo、Router.navigateTo、<navigator open-type="navigateTo"/>触发。
wx.navigateTo的目标必须是非tarbar页面。
3.页面重定向:opentype:redirectTo
打开一个新页面替换当前栈顶页面(先弹出栈顶页面,再将新页面推入栈中)。
可通过wx.redirectTo、Router.redirectTo、<navigator open-type="redirectTo"/>触发。
wx.redirectTo的目标必须是非tarbar页面。
4.页面返回:openType: navigateBack
实现页面回退,会将当前栈顶页面依次弹出并销毁。
可通过wx.navigateBack、Router.navigateBack、<navigator open-type="navigateBack"/>、用户点击左上角返回按钮或按设备上的返回键触发。
当栈的元素数量只有1个时,调用navigateBack将会报错。
5.Tab 切换:openType: switchTab
可切换到指定的TabBar页面
可通过wx.switchTab、Router.switchTab、<navigator open-type="switchTab"/>、用户点击TabBar中的按钮触发。
6. 重加载:openType: reLaunch, autoReLaunch
重加载表示销毁当前所有页面,并重新载入一个新页面。
reLaunch与autoRelaunch的区别是:reLaunch是由开发者触发,autoRelaunch是由用户或自动触发。
可通过wx.reLaunch、Router.reLaunch、<navigator open-type="reLaunch">触发reLaunch。小程序处于后台时,用户从扫码或分享等场景重新进入小程序时触发autoRelaunch。
7.关闭小窗页面:openType: dismissPip
表示关闭一个正处于小窗模式的页面。
页面路由监听
从基础库3.5.5开始,小程序提供了一套监听路由事件的函数。有以下这些监听函数:
wx.onBeforeAppRoute:路由事件下发到基础库,基础库执行路由逻辑前触发wx.onAppRoute:路由事件下发到基础库,基础库执行路由逻辑后触发wx.onAppRouteDone:路由对应的动画(页面推入、推出等)完成时触发wx.onBeforePageLoad:路由引发的页面创建之前触发wx.onAfterPageLoad:路由引发的页面创建完成后触发wx.onBeforePageUnload:路由引发的页面销毁之前触发wx.onAfterPageUnload:路由引发的页面销毁完成后触发
在路由监听函数中,还带上了全局唯一的路由事件id,通过回调参数获取
wx.onAppRoute(res=>{
console.log(res.routeEventId);
})模块化
定义
// indexUtil.js
function sayHello(name) {
console.log(`Hello ${name} !`)
}
module.exports.sayHello = sayHello;引用
const indexUtil = require("./indexUtil");
Page({
tapButton12: function (event) {
indexutil.sayHello("user");
}
});兼容性
小程序还提供了wx.canIUse这个API,用于判断接口或者组件在当前宿主环境是否可用,其参数格式为: ${API}.${method}.${param}.${options}或者${component}.${attribute}.${option}
wx.canIUse("getSystemInfo")API
小程序开发框架提供了丰富的API,主要分为以下几类:
- 事件监听API:用于监听某个事件是否触发,一般以wx.on开头的api。这类api接受一个回调函数作为参数。如路由监听函数
wx.onAppRoute、wx.onBeforeAppRoute等。 - 同步API:以sync结尾的api。api的结果会同步返回。如:
wx.setStorageSync,wx.getSystemInfoSync - 异步API:目前大多数API都是异步API,如:
wx.request。异步API一般会接受一个Object对象作为参数。Object对象包含:success回调方法、fail回调方法、complete回调方法、其他接口定义的参数。 - PromiseAPI:基础库 2.10.2 版本起,异步 API 支持 callback & promise 两种调用方式。当接口参数 Object 对象中不包含 success/fail/complete 时将默认返回 promise,否则仍按回调方式执行,无返回值。
如异步api本身就有返回值的,则不提供PromiseAPI,需要开发者自行封装。
- 云开发API:可以在小程序端调用云函数。
wx.cloud.callFunction({
name:"函数名,
data:{
//参数
},
success:function(res){
console.log("success")
},
fail:function(){
console.log("fail")
}
})常用API
发起网络请求
使用wx.request发起网络请求。
tapButton4: function (event) {
wx.request({
url: 'https://www.baidu.com/',
success: function (result) {
console.log(result);
}
})
},wx.request支持单独设置超时时间,通过timeout属性设置,默认为60000ms。也支持在小程序配置文件app.js中,设置全局超时时间。
{
"networkTimeout": {
"request": 20000,
"connectSocket": 20000,
"uploadFile": 20000,
"downloadFile": 20000
}
}微信登录
通过wx.login()接口获取登录令牌code,再通过登录令牌向微信服务器发送请求获取用户的openid。
tapButton6: function (event) {
wx.login({
success: (res) => {
wx.login({
success: (res) => {
console.log(res);
wx.request({
url: 'https://api.weixin.qq.com/sns/jscode2session',
data: {
//appid和secret通过微信小程序管理后台获取。
"appid": "wxf1f154e90afef20a",
"secret": "123",
"js_code": res.code,
"grant_type": "authorization_code"
},
success: function (res) {
console.log(res);
}
})
},
})
},
})
},本地数据缓存
小程序提供了本地数据缓存接口,用于获取、设置、删除本地数据。通过key/value的方式管理本地数据。
wx.setStorage、wx.setStorageSyncwx.getStorage、wx.getStorageSyncwx.removeStorage、wx.removeStoageSync
tapButton7: function (event) {
//获取本地数据
wx.getStorage({
key: "money",
success: (data) => {
console.log(data);
}
});
//删除本地数据
wx.removeStorage({
key: 'money',
success: function (res) {
console.log(res);
}
});
//设置本地数据
wx.setStorage({
key: "money",
data: 10,
success: function (res) {
console.log(res);
}
});
}本地数据最多可缓存10M大小的数据。一般用于缓存不常更新的数据,减少网络请求,从而提高小程序的性能。
本地缓存通过微信账号、小程序维度对数据进行隔离。
常用设备能力
扫描二维码
通过wx.scanCode调用扫描二维码的能,它会将识别到的二维码信息返回给success回调函数。
tapButton8: function (event) {
console.log(123);
wx.scanCode({
success: function (res) {
console.log(res);
wx.showToast({
title: res.result,
})
},
fail: function (error) {
console.log(error);
}
})
}模拟器扫码可能会报错
获取网络状态
通过wx.getNetworkType获取当前所处的网络环境,可以是wifi、4g、5g
tapButton9: function (event) {
wx.getNetworkType({
success: function (res) {
console.log(res);
}
})
}
NPM支持
小程序目前已支持使用npm安装第三方包,但对于npm有一定限制:
- 不支持依赖node.js内置库的包
- 不支持依赖浏览器内置对象的包
- 不支持依赖C++插件的包
全局数据共享
小程序中使用MobX为全局数据共享的解决方案,分为两步:1是创建全局数据共享对象。2是将全局数据共享对象绑定到页面或组件上。
创建全局数据共享块
通过创建一个observable对象的方式定义全局数据共享块。
observable对象中可以包含:
- data:全局共享的数据。
- get:计算属性。
- action函数:用于执行数据的更新操作。不建议直接通过data修改。action函数里面包含一个更新数据的function。
//store.js
import {observable} from 'mobx-miniprogram'
export const store=observable({
num1:1,
num2:2,
get sum(){
return this.num1+this.num2;
},
updateNum1:action(function(newNum){
this.num1=newNum;
})
updateNum2:action(function(step){
this.num2+=step;
})
})将全局共享对象绑定到页面
导入mobx-miniprogram-bindings包的createStoreBindings方法和上面store.js导出的store对象。
在页面的onload方法中,调用createStoreBindings方法绑定store对象的数据、计算属性和action到当前页面。
//page.js
import {creareStoreBindings} from 'mobx-miniprogram-bindings';
import store from 'store.js'
Page({
onLoading:function(){
this.storeBindings=createStoreBindings(this,
{
store,
fields:[data1,data2,compute1,compute2,...],
actions:[action1,action2,action3,...]
})
},
onUnload:function(){
this.storeBindings.destoryStoreBindings();
}
})将全局共享对象绑定到组件
分包
将一个完整的小程序划分成几个子包,用户在使用时按需加载。
配置app.js的subpackages属性下的包为分包,分包可以引用主包的内容。
{
"subpackages":[
{
"root":"packageA",
"name":"p1",
"page":[
"pages/cat",
"pages/dog"
]
},
{
"root":"packageB",
"name":"p2",
"page":[
"pages/apple",
"pages/banana"
]
},
]
}分包目录与主包目录平级,目录名为包名。 
独立分包
独立分包是指可以独立于主包和其他分包而单独运行的包。
通过independent属性标识为分包为独立分包。
{
"subpackages":[
{
"root":"pkgA",
"name":"p1",
"page":[
"pages/cat/cat",
"pages/dog/dog"
]
},
{
"root":"pkgB",
"name":"p2",
"page":[
"pages/bird/bird",
"pages/fish/fish"
],
"independent":true
},
]
}独立分包与主包、其他分包之间是相互隔绝的,不能互相引用彼此的资源。
分包预下载
分包预下载是小程序的一个功能,是指当用户进入到指定页面时触发预下载分包资源,从而提高打开分包页面的速度。
分包预下载规则通过app.js的preloadRule节点配置。
{
"preloadRule":{
"pages/content/content":{
"network":"all",
"packages":[
"p1",
"p2"
]
}
}
}上面配置意思是,当用户进入到pages/content/content页面时,预下载p1、p2包。
数据通信机制
由于小程序特殊的宿主环境和实现方案,小程序的逻辑层与视图层通讯有不同的机制,可以分为:
- 逻辑层向视图层通信
- 视图层向逻辑层通信
- 逻辑层与原生组件通信
逻辑层向视图层通信
逻辑层通过data、setData向视图层传递数据。
在页面第一次创建时,
- 逻辑层初始化Page对象和视图层初始化wxml结构,
- 之后逻辑层会向视图层传递data数据,
- 视图层接收数据,并进行初始化渲染。
- 最后回调逻辑层的回调函数。
当逻辑层调用setData时, - 视图层获取到数据后会创建新的wxml节点树。
- 将data套用到新节点树上。
- 然后将新树与当前节点树进行比较,得到节点树需要更新或删除的节点或属性,之后得到最终的新节点数,
- 之后逻辑层将setData的数据与当前data数据合并
- 最后新节点树替换掉当前节点树,用于下次重渲染。

视图层向逻辑层通信
当用户触发事件如单击事件时,如果事件存在绑定的回调函数,视图层会将事件及事件数据传递到逻辑层。
逻辑层收到事件后,执行回调逻辑。
由于这个过程涉及到两个进程间的通信,所以会存在一定延迟,应避免传递过多的数据。
逻辑层与原生组件通信
逻辑层与原生组件的通信,一般通过原生组件提供的context完成。
相比于与setData,将数据通过原生native转发,再传递到视图层webview。原生组件使用context将数据从逻辑层传递到native,延迟会更低。 
Skyline渲染引擎
Skyline是一个新的渲染引擎,相比于webView,Skyline更加注重性能。
可以通过配置选项设置页面的渲染引擎
// page.json
// skyline 渲染
{
"renderer": "skyline"
}
// webview 渲染
{
"renderer": "webview"
}