小程序基础
小程序指南
参考
参考文档:小程序官方文档
注册小程序
宿主环境提供了 App()
构造器用来注册一个程序App,必须写在项目根目录的app.js里, App 实例是单例对象,在其他 JS 脚本中可以使用宿主环境提供的 getApp()
来获取程序实例。
App({
onLaunch: function(options) { console.log(options) },
onShow: function(options) { console.log(options) }
})
App构造器接受一个Object参数。
参数属性 | 类型 | 描述 |
---|---|---|
onLaunch | Function | 当小程序初始化完成时,会触发 onLaunch(全局只触发一次) |
onShow | Function | 当小程序启动,或从后台进入前台显示,会触发 onShow |
onHide | Function | 当小程序从前台进入后台,会触发 onHide |
onError | Function | 当小程序发生脚本错误,或者 API 调用失败时,会触发 onError 并带上错误信息 |
其他字段 | 任意 | 可以添加任意的函数或数据到 Object 参数中,在App实例回调用 this 可以访问 |
目录结构
项目的根目录
文件 | 必需 | 作用 |
---|---|---|
app.js | 是 | 小程序逻辑 |
app.json | 是 | 小程序公共配置 |
app.wxss | 否 | 小程序公共样式表 |
全局数据
// app.js
App({
globalData: 'I am global data' // 全局共享数据
})
// 其他页面脚本other.js
var appInstance = getApp()
console.log(appInstance.globalData) // 输出: I am global data
注意
所有页面的脚本逻辑都跑在同一个JsCore线程,页面使用setTimeout
或者setInterval
的定时器,然后跳转到其他页面时,这些定时器并没有被清除,需要开发者自己在页面离开的时候进行清理。
页面
页面组成
一个页面是分三部分组成:界面、配置和逻辑。界面由WXML
文件和WXSS
文件来负责描述,配置由JSON
文件进行描述,页面逻辑则是由JS
脚本文件负责。一个页面的文件需要放置在同一个目录下,其中WXML文件和JS文件是必须存在的,JSON和WXSS文件是可选的。
页面路径需要在小程序代码根目录app.json中的pages字段声明,否则这个页面不会被注册到宿主环境中。
{
"pages":[
"pages/index/page", // 第一项默认为首页
"pages/other/other"
]
}
页面注册与生命周期
宿主环境提供了 Page()
构造器用来注册一个小程序页面,Page()
在页面脚本page.js中调用,Page构造器接受一个Object参数。
Page({
data: { text: "This is page data." },
onLoad: function(options) { },
onReady: function() { },
onShow: function() { },
onHide: function() { },
onUnload: function() { },
onPullDownRefresh: function() { },
onReachBottom: function() { },
onShareAppMessage: function () { },
onPageScroll: function() { }
})
参数属性 | 类型 | 描述 |
---|---|---|
data | Object | 页面的初始数据 |
onLoad | Function | 生命周期函数--监听页面加载,触发时机早于onShow和onReady |
onReady | Function | 生命周期函数--监听页面初次渲染完成 |
onShow | Function | 生命周期函数--监听页面显示,触发事件早于onReady |
onHide | Function | 生命周期函数--监听页面隐藏 |
onUnload | Function | 生命周期函数--监听页面卸载 |
onPullDownRefresh | Function | 页面相关事件处理函数--监听用户下拉动作 |
onReachBottom | Function | 页面上拉触底事件的处理函数 |
onShareAppMessage | Function | 用户点击右上角转发 |
onPageScroll | Function | 页面滚动触发事件的处理函数 |
其他 | Any | 可以添加任意的函数或数据,在Page实例的其他函数中用 this 可以访问 |
页面路由
小程序把页面的打开路径定义成页面URL,其组成格式和网页的URL类似,在页面路径后使用英文 ? 分隔path和query部分,query部分的多个参数使用 &
进行分隔,参数的名字和值使用 key=value
的形式声明。在页面Page构造器里onLoad
的option可以拿到当前页面的打开参数,其类型是一个Object,其键值对与页面URL上query键值对一一对应。和网页URL一样,页面URL上的value如果涉及特殊字符(例如:&
字符、?
字符、中文字符等,详情参考URI的RFC3986说明 ),需要采用UrlEncode后再拼接到页面URL上。
// pages/list/list.js
// 列表页使用navigateTo跳转到详情页
wx.navigateTo({ url: 'pages/detail/detail?id=1&other=abc' })
// pages/detail/detail.js
Page({
onLoad: function(option) {
console.log(option.id)
console.log(option.other)
}
})
路由方式 | 触发时机 | 路由前页面生命周期 | 路由后页面生命周期 |
---|---|---|---|
初始化 | 小程序打开的第一个页面 | onLoad, onShow | |
打开新页面 调用 | API wx.navigateTo | onHide | onLoad, onShow |
页面重定向 调用 | API wx.redirectTo | onUnload | onLoad, onShow |
页面返回 调用 | API wx.navigateBack | onUnload | onShow |
Tab | 切换 调用 API wx.switchTab | ||
重启动 | 调用 API wx.reLaunch | onUnload | onLoad, onShow |
页面的数据
页面Page构造器的data字段保存页面的数据,data参数是页面第一次渲染时从逻辑层传递到渲染层的数据。 我们可以在Page实例下的方法调用this.setData
把数据传递给渲染层,从而达到更新界面的目的。
setData其一般调用格式是 setData(data, callback)
,其中data是由多个key: value
构成的Object对象。
<!-- page.wxml -->
<view>{{text}}</view>
<view>{{array[0].msg}}</view>
// page.js
Page({
data: {
text: 'init data',
array: [{msg: '1'}, {msg: '2'}]
},
onLoad: function(){
this.setData({
text: 'change data'
}, function(){
// 在这次setData对界面渲染完毕后触发
})
}
})
组件
一个小程序页面可以分解成多个部分组成,组件就是小程序页面的基本组成单元。
组件是在WXML模板文件声明中使用的,WXML的语法和HTML语法相似,小程序使用标签名来引用一个组件,通常包含开始标签和结束标签,该标签的属性用来描述该组件。
<!-- page.wxml -->
<image mode="scaleToFill" src="img.png"></image>
事件
常见的事件类型:
类型 | 触发条件 |
---|---|
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 动画完成时触发 |
当事件回调触发的时候,会收到一个事件对象,对象的详细属性如下表所示:
属性 | 类型 | 说明 |
---|---|---|
type | String | 事件类型 |
timeStamp | Integer | 页面打开到触发事件所经过的毫秒数 |
target | Object | 触发事件的组件的一些属性值集合 |
currentTarget | Object | 当前组件的一些属性值集合 |
detail | Object | 额外的信息 |
touches | Array | 触摸事件,当前停留在屏幕中的触摸点信息的数组 |
changedTouches | Array | 触摸事件,当前变化的触摸点信息的数组 |
target和currentTarget的区别,currentTarget为当前事件所绑定的组件,而target则是触发该事件的源头组件。
target和currentTarget事件对象属性:
属性 | 类型 | 说明 |
---|---|---|
id | String | 当前组件的id |
tagName | String | 当前组件的类型 |
dataset | Object | 当前组件上由data-开头的自定义属性组成的集合 |
关于touch和changedTouches对象的详细参数:
属性 | 类型 | 说明 |
---|---|---|
identifier | Number | 触摸点的标识符 |
pageX, pageY | Number | 距离文档左上角的距离,文档的左上角为原点 ,横向为X轴,纵向为Y轴 |
daclientX, clientYtaset | Number | 距离页面可显示区域(屏幕除去导航条)左上角距离,横向为X轴,纵向为Y轴 |
事件流和事件传播机制
- 事件流: 事件从树顶端开始向下传递到目标元素的过程称为“捕获”,从目标元素返回树顶端的过程称为“冒泡”。
- 获阶段: 事件从树的根部开始向下传递,直到达到目标元素。在此阶段,currentTarget指向路径上的当前元素,而target指向被单击的对象。
- 目标阶段: 事件到达目标元素。在此阶段,target和currentTarget都指向目标元素。
- 冒泡阶段: 事件从目标元素返回,向上传递到树的根部。在此阶段,currentTarget和target都指向目标元素。
事件绑定与冒泡捕获
事件绑定的写法和组件属性一致,以key="value"
的形式,其中:
- key以bind或者catch开头,然后跟上事件的类型,如bindtap、catchtouchstart。自基础库版本1.5.0起,bind和catch后可以紧跟一个冒号,其含义不变,如bind:tap、catch:touchstart。同时bind和catch前还可以加上capture-来表示捕获阶段。
- value是一个字符串,需要在对应的页面Page构造器中定义同名的函数,否则触发事件时在控制台会有报错信息。
提示
- bind事件绑定不会阻止冒泡事件向上冒泡,catch事件绑定可以阻止冒泡事件向上冒泡。
- capture-bind:这是一种在捕获阶段绑定事件的方式。在捕获阶段,事件从外层元素向内层元素传递,而不是从内层向外层传递(如冒泡阶段),而bind事件相反,事件会从子组件向父组件传递。
关键帧动画
接口:this.animate(selector, keyframes, duration, callback)
参考: https://developers.weixin.qq.com/miniprogram/dev/framework/view/animation.html
自定义组件
创建自定义组件:
- json 中 :"component": true
- 组件模板
<!-- 这是自定义组件的内部WXML结构 -->
<view class="inner">
{{innerText}}
</view>
<slot></slot>
/* 这里的样式只应用于这个自定义组件 */
.inner {
color: red;
}
注意
注意:在组件wxss中不应使用ID选择器、属性选择器和标签名选择器。
Component({
properties: {
// 这里定义了innerText属性,属性值可以在组件使用时指定
innerText: {
type: String,
value: 'default value',
}
},
data: {
// 这里是一些组件内部数据
someData: {}
},
methods: {
// 这里是一个自定义方法
customMethod: function(){}
}
})
使用自定义组件
{
"usingComponents": {
"component-tag-name": "path/to/the/custom/component"
}
}
Component 构造器
Component({
behaviors: [],
properties: {
myProperty: { // 属性名
type: String,
value: ''
},
myProperty2: String // 简化的定义方式
},
data: {}, // 私有数据,可用于模板渲染
lifetimes: {
// 生命周期函数,可以为函数,或一个在methods段中定义的方法名
attached: function () { },
moved: function () { },
detached: function () { },
},
// 生命周期函数,可以为函数,或一个在methods段中定义的方法名
attached: function () { }, // 此处attached的声明会被lifetimes字段中的声明覆盖
ready: function() { },
pageLifetimes: {
// 组件所在页面的生命周期函数
show: function () { },
hide: function () { },
resize: function () { },
},
methods: {
onMyButtonTap: function(){
this.setData({
// 更新属性和数据的方法与更新页面数据的方法类似
})
},
// 内部方法建议以下划线开头
_myPrivateMethod: function(){
// 这里将 data.A[0].B 设为 'myPrivateData'
this.setData({
'A[0].B': 'myPrivateData'
})
},
_propertyChange: function(newVal, oldVal) {
}
}
})