1 data
data 是页面第一次渲染使用的初始数据。页面加载时,data 将会以JSON字符串的形式由逻辑层传至渲染层,因此data中的数据必须是可以转成JSON的类型:字符串,数字,布尔值,对象,数组。
wxml里的代码:
<view>{% raw %}{{% endraw %}{text}}</view>
<view>{% raw %}{{% endraw %}{array[0].msg}}</view>
js里的data模型:
Page({
data: {
text: 'init data',
array: [{msg: '1'}, {msg: '2'}]
}
})
2 生命周期函数
-
onLoad(Object query)
页面加载时触发。一个页面只会调用一次,可以在 onLoad 的参数中获取打开当前页面路径中的参数。 -
onShow()
页面显示/切入前台时触发。 -
onReady()
页面初次渲染完成时触发。一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互。 -
onHide()
页面隐藏/切入后台时触发。 如 navigateTo 或底部 tab 切换到其他页面,小程序切入后台等。 -
onUnload()
页面卸载时触发。如redirectTo或navigateBack到其他页面时。
需要注意的是:对界面内容进行设置的 API 如wx.setNavigationBarTitle,请在onReady之后进行。
可以通过一个简单的例子来测试执行顺序:
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
console.log("页面加载时触发")
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
console.log("onReady:监听页面初次渲染完成");
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
console.log("onShow:页面显示时触发");
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
console.log("页面隐藏时触发");
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
console.log("页面卸载时触发");
}
})
3 模块化
官网地址:https://developers.weixin.qq.com/miniprogram/dev/framework/app-service/module.html
uitls文件用来存放一些js文件,这些js文件里包含了一些用在全局的js共用方法等,通常也被工具包,我们根据项目需要在里面添加工具类,将一些公共的代码抽离成为一个单独的 js 文件,作为一个模块。模块只有通过 module.exports 或者 exports 才能对外暴露接口。
举例说明:
- 第一步:我们在uitls里自顶一个commen.js文件,并书写两个方法:
- 第二步:在一个页面里来使用这两个方法,在使用这个模块方法之前,需要使用使用
require(path)
将公共代码引入,比如我们可以在pages/notice/notice.js 里Page({})里进行测试。
// pages/notice/notice.js
var commonjs=require("../../utils/common.js")
Page({
/**
* 页面的初始数据
*/
data: {},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
commonjs.fn1("hello!")
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
commonjs.fn2("bye!")
}
})
页面的控制台里显示:
4 全局变量的使用
全局js配置文件,小程序加载时先运行这个文件,这里定义的变量为全局变量,可在页面内通过 getApp() 获取,现在通过一个例子来进行说明:
第一步:在app.js 里的globalData里定义一个空变量
第二步:在pages/notice/notice.js 里书写代码
// pages/notice/notice.js
var commonjs=require("../../utils/common.js")
var app=getApp();
Page({
/**
* 页面的初始数据
*/
data: {},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
commonjs.fn1("hello!");
app.globalData.appName="完美校园";
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
commonjs.fn2("bye!");
console.log(app.globalData.appName);
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {}
})
5. 数据绑定
数据绑定使用 Mustache 语法(双大括号)将变量包起来,用法和Vuejs非常相似:
5.1 内容
<view>{% raw %}{{% endraw %}{ message }}</view>
Page({
data: {
message: 'Hello world!'
}
})
5.2 组件属性(需要在双引号之内)
<view id="item-{% raw %}{{% endraw %}{id}}"></view>
Page({
data: {
id: 0
}
})
5.3 控制属性(需要在双引号之内)
<view wx:if="{% raw %}{{% endraw %}{condition}}"></view>
Page({
data: {
condition: true
}
})
5.4 关键字(需要在双引号之内)
true
:boolean 类型的 true,代表真值。
false
: boolean 类型的 false,代表假值。
<checkbox checked="{% raw %}{{% endraw %}{false}}"></checkbox>
特别注意:不要直接写 checked=“false”,其计算结果是一个字符串,转成 boolean 类型后代表真值。
5.5 运算
可以在{ { } }内进行简单的运算,支持的有如下几种方式:
- 三元运算
<view hidden="{% raw %}{{% endraw %}{flag ? true : false}}">Hidden</view>
- 算术运算
<view>{% raw %}{{% endraw %}{a + b}} + {% raw %}{{% endraw %}{c}} + d</view>
Page({
data: {
a: 1,
b: 2,
c: 3
}
})
view中的内容为 3 + 3 + d
。
- 逻辑判断
<view wx:if="{% raw %}{{% endraw %}{length > 5}}"></view>
- 字符串运算
<view>{% raw %}{{% endraw %}{"hello" + name}}</view>
Page({
data: {
name: 'MINA'
}
})
- 数据路径运算
<view>{% raw %}{{% endraw %}{object.key}} {% raw %}{{% endraw %}{array[0]}}</view>
Page({
data: {
object: {
key: 'Hello '
},
array: ['MINA']
}
})
- 组合
也可以在 Mustache 内直接进行组合,构成新的对象或者数组。
- 数组
<view wx:for="{% raw %}{{% endraw %}{[zero, 1, 2, 3, 4]}}">{% raw %}{{% endraw %}{item}}</view>
Page({
data: {
zero: 0
}
})
最终组合成数组[0, 1, 2, 3, 4]
。
- 对象
<template is="objectCombine" data="{% raw %}{{% endraw %}{for: a, bar: b}}"></template>
Page({
data: {
a: 1,
b: 2
}
})
最终组合成的对象是{for: 1, bar: 2}
也可以用扩展运算符 ...
来将一个对象展开
<template is="objectCombine" data="{% raw %}{{% endraw %}{...obj1, ...obj2, e: 5}}"></template>
Page({
data: {
obj1: {
a: 1,
b: 2
},
obj2: {
c: 3,
d: 4
}
}
})
最终组合成的对象是 {a: 1, b: 2, c: 3, d: 4, e: 5}。
如果对象的 key 和 value 相同,也可以间接地表达。
<template is="objectCombine" data="{% raw %}{{% endraw %}{foo, bar}}"></template>
Page({
data: {
foo: 'my-foo',
bar: 'my-bar'
}
})
最终组合成的对象是 {foo: ‘my-foo’, bar:‘my-bar’}。
注意:上述方式可以随意组合,但是如有存在变量名相同的情况,后边的会覆盖前面,如:
<template is="objectCombine" data="{% raw %}{{% endraw %}{...obj1, ...obj2, a, c: 6}}"></template>
Page({
data: {
obj1: {
a: 1,
b: 2
},
obj2: {
b: 3,
c: 4
},
a: 5
}
})
最终组合成的对象是 {a: 5, b: 3, c: 6}
。
注意: 花括号和引号之间如果有空格,将最终被解析成为字符串
<view wx:for="{% raw %}{{% endraw %}{[1,2,3]}} ">
{% raw %}{{% endraw %}{item}}
</view>
等同于
<view wx:for="{% raw %}{{% endraw %}{[1,2,3] + ' '}}">
{% raw %}{{% endraw %}{item}}
</view>
6. 条件渲染
- wx:if
在框架中,使用 wx:if="{% raw %}{{% endraw %}{condition}}" 来判断是否需要渲染该代码块:
<view wx:if="{% raw %}{{% endraw %}{condition}}">True</view>
- 也可以用 wx:elif 和 wx:else 来添加一个 else 块:
<view wx:if="{% raw %}{{% endraw %}{length > 5}}">1</view>
<view wx:elif="{% raw %}{{% endraw %}{length > 2}}">2</view>
<view wx:else>3</view>
- block wx:if
因为 wx:if 是一个控制属性,需要将它添加到一个标签上。如果要一次性判断多个组件标签,可以使用一个<block/>
标签将多个组件包装起来,并在上边使用 wx:if 控制属性。
<block wx:if="{% raw %}{{% endraw %}{true}}">
<view>view1</view>
<view>view2</view>
</block>
注意: <block/>
并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性
7. 列表渲染
7.1 wx:for
在组件上使用 wx:for
控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。
默认数组的当前项的下标变量名默认为 index
,数组当前项的变量名默认为 item
<view wx:for="{% raw %}{{% endraw %}{array}}">
{% raw %}{{% endraw %}{index}}: {% raw %}{{% endraw %}{item.message}}
</view>
Page({
data: {
array: [{
message: 'foo',
}, {
message: 'bar'
}]
}
})
使用 wx:for-item
可以指定数组当前元素的变量名,使用 wx:for-index
可以指定数组当前下标的变量名:
<view wx:for="{% raw %}{{% endraw %}{array}}" wx:for-index="idx" wx:for-item="itemName">
{% raw %}{{% endraw %}{idx}}: {% raw %}{{% endraw %}{itemName.message}}
</view>
wx:for
也可以嵌套,下边是一个九九乘法表
<view wx:for="{% raw %}{{% endraw %}{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="i">
<view wx:for="{% raw %}{{% endraw %}{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="j">
<view wx:if="{% raw %}{{% endraw %}{i <= j}}">
{% raw %}{{% endraw %}{i}} * {% raw %}{{% endraw %}{j}} = {% raw %}{{% endraw %}{i * j}}
</view>
</view>
</view>
7.2 block wx:for
类似 block wx:if
,也可以将 wx:for
用在<block/>
标签上,以渲染一个包含多节点的结构块。例如:
<block wx:for="{% raw %}{{% endraw %}{[1, 2, 3]}}">
<view>{% raw %}{{% endraw %}{index}}:</view>
<view>{% raw %}{{% endraw %}{item}}</view>
</block>
7.3 wx:key
如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 <input>
中的输入内容,<switch>
的选中状态),需要使用 wx:key
来指定列表中项目的唯一的标识符。
wx:key
的值以两种形式提供
- 字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。
- 保留关键字
*this
代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字,如:
当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。
如不提供 wx:key,会报一个 warning, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略。
示例代码:
<switch wx:for="{% raw %}{{% endraw %}{objectArray}}" wx:key="unique" style="display: block;">
{% raw %}{{% endraw %}{item.id}}
</switch>
<button bindtap="switch">Switch</button>
<button bindtap="addToFront">Add to the front</button>
<switch wx:for="{% raw %}{{% endraw %}{numberArray}}" wx:key="*this" style="display: block;">
{% raw %}{{% endraw %}{item}}
</switch>
<button bindtap="addNumberToFront">Add to the front</button>
Page({
data: {
objectArray: [
{id: 5, unique: 'unique_5'},
{id: 4, unique: 'unique_4'},
{id: 3, unique: 'unique_3'},
{id: 2, unique: 'unique_2'},
{id: 1, unique: 'unique_1'},
{id: 0, unique: 'unique_0'},
],
numberArray: [1, 2, 3, 4]
},
switch(e) {
const length = this.data.objectArray.length
for (let i = 0; i < length; ++i) {
const x = Math.floor(Math.random() * length)
const y = Math.floor(Math.random() * length)
const temp = this.data.objectArray[x]
this.data.objectArray[x] = this.data.objectArray[y]
this.data.objectArray[y] = temp
}
this.setData({
objectArray: this.data.objectArray
})
},
addToFront(e) {
const length = this.data.objectArray.length
this.data.objectArray = [{id: length, unique: 'unique_' + length}].concat(this.data.objectArray)
this.setData({
objectArray: this.data.objectArray
})
},
addNumberToFront(e) {
this.data.numberArray = [this.data.numberArray.length + 1].concat(this.data.numberArray)
this.setData({
numberArray: this.data.numberArray
})
}
})
注意:
当 wx:for
的值为字符串时,会将字符串解析成字符串数组
<view wx:for="array">
{% raw %}{{% endraw %}{item}}
</view>
等同于
<view wx:for="{% raw %}{{% endraw %}{['a','r','r','a','y']}}">
{% raw %}{{% endraw %}{item}}
</view>
注意: 花括号和引号之间如果有空格,将最终被解析成为字符串
<view wx:for="{% raw %}{{% endraw %}{[1,2,3]}} ">
{% raw %}{{% endraw %}{item}}
</view>
等同于
<view wx:for="{% raw %}{{% endraw %}{[1,2,3] + ' '}}">
{% raw %}{{% endraw %}{item}}
</view>
8. 事件
- 事件是视图层到逻辑层的通讯方式。
- 事件可以将用户的行为反馈到逻辑层进行处理。
- 事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数。
- 事件对象可以携带额外信息,如 id, dataset, touches。
在小程序中,用户使用的最多的操作几种事件分别是点击、拖动、双击、输入
【举例说明】:
- 在组件中绑定一个事件处理函数。
如bindtap
,当用户点击该组件的时候会在该页面对应的Page中找到相应的事件处理函数。
<view id="tapTest" data-hi="微信" bindtap="tapName">点我</view>
- 在相应的Page定义中写上相应的事件处理函数,参数是event。
Page({
tapName(event) {
console.log(event)
}
})
- 可以看到log出来的信息大致如下:
{
"type": "tap",
"timeStamp": 895,
"target": {
"id": "tapTest",
"dataset": {
"hi": "WeChat"
}
},
"currentTarget": {
"id": "tapTest",
"dataset": {
"hi": "微信"
}
},
"detail": {
"x": 53,
"y": 14
},
"touches": [
{
"identifier": 0,
"pageX": 53,
"pageY": 14,
"clientX": 53,
"clientY": 14
}
],
"changedTouches": [
{
"identifier": 0,
"pageX": 53,
"pageY": 14,
"clientX": 53,
"clientY": 14
}
]
}
9. 和后台数据进行交互
官网地址:https://developers.weixin.qq.com/miniprogram/dev/api/wx.request.html
在index.wxml 文件中添加两个组件
<view>{% raw %}{{% endraw %}{ msg }}</view>
<button bindtap="bindViewTap">点击我</button>
在js文件里书写bindViewTap方法
Page({
data: {},
//事件处理函数
bindViewTap1: function () {
var _this = this;
var msgFromBack = "";
wx.request({
url: 'http://localhost:3004/index', // 仅为示例,并非真实的接口地址
data: {},
header: {
'content-type': 'application/json' // 默认值
},
success(res) {
console.log(res.data);
//查看官方api方法
msgFromBack = res.data.comments;
_this.setData(res.data);//统一赋值
_this.setData({
msg: msgFromBack
});//单属性赋值
}
})
}
})