1.工具(vscode环境)
- JavaScript (ES6) code snippets :ES6语法提示,代码片段
- minapp:小程序代码补全(标签/属性)提示
- wechat-sinppet:小程序代码补全(小程序API)提示,如wx-request
- wxapp-helper:小程序助手,模拟 Web 开发者工具的创建等功能
2.小程序文件结构与基本项目目录
文件结构:
结构 | 传统web | 微信小程序 |
---|---|---|
结构 | HTML | WXML |
样式 | CSS | WXSS |
逻辑 | Javascript | Javascript |
配置 | 无 | JSON |
基本项目目录:
3.小程序常用语法(与vue写法类似)
1.模板展示数据
<!-- 展示数据 -->
<view>数字:{{ num }}</view>
Page({
data:{
num:100
},
getAndUpdate(){
//更新数据
this.setData({
num: 101
});
//获取数据
console.log(this.data.num);
}
})
tips:小程序为单向数据流,model-view
tips:this.setData({},callback)
特点:
- 1.同步修改:this.data被同步修改
- 2.异步更新:异步将setData函数用于将数据从逻辑层发送到视图层
- 单次设置的数据不能超过1024kb,请尽量避免一次设置过多的数据。
- 请不要把 data 中任何一项的 value 设为
undefined
,否则这一项将不被设置并可能遗留一些潜在问题
2.布尔类型注意点
<!-- 布尔类型不加双括号会被当成字符串 -->
<view wx:if="{{ true }}" >哈哈哈</view>
或者
<view wx:if="{{ isShow }}" >哈哈哈</view>
//js
Page({
data:{
isShow:false
}
})
不能这样使用
//该方式wx:if会把false当成字符串进行隐式转换
<view wx:if="false" >哈哈哈</view>
3.条件渲染
<view wx:if="{{ false }}" >哈哈哈</view>
<view wx:if="{{false}}">1</view>
<view wx:elif="{{true}}">2</view>
<view wx:else>3</view>
<!-- hidden 通过display:none来实现显示隐藏-->
<view hidden="{{isShow}}">
啦啦啦啦啊
</view>
4.循环遍历
<!-- wx:for循环 -->
<!-- for循环 当对象数组中有唯一值时,取其中一个唯一值作为key;没有时则不写 -->
<!-- for循环默认index为索引,item为项;通过wx:for-index变更索引名,通过wx:for-item变更item名 -->
<view wx:for="{{list}}" wx:key="id">
<view>{{index}} -- {{item.name}}</view>
<view wx:if="{{item.children}}">
<view wx:for="{{item.children}}" wx:for-index="num" wx:for-item="it" wx:key="id">
<view>{{item.name}} ==> {{num}} -- {{it.name}}</view>
</view>
</view>
</view>
<!-- 数组,当有唯一值时,key使用*this;当无唯一值时,key则不写或随便写 -->
<view wx:for="{{arr}}" wx:key="*this">
<view>{{item}}</view>
</view>
Page({
data:{
list:[
{
id:1,
name:'哈哈'
},
{
id:'2',
name:'呵呵',
children:[
{
id:1,
name:'呵呵的孩子1'
},
{
id:2,
name:'呵呵的孩子2'
}
]
}
],
arr:[1,2,3,4,5]
}
})
5.事件绑定
小程序中绑定事件,通过bind关键字来实现。如 bindtap(点击事件),
bindinput,
bindchange
等
tips:bind绑定(如bindtap):事件绑定会冒泡;catch绑定(catchtap):事件绑定阻止冒泡
一个双向数据绑定示例:
<input type="text" value="{{msg}}" bindinput="handleInput"/>
<view>{{ msg }}</view>
Page({
data:{
msg:'呵呵'
},
handleInput(e){
console.log('e:',e);
this.setData({
msg: e.detail.value
});
}、
})
效果:
tips:
1.绑定事件时不能带参数 不能带括号,如下
<input bindinput="handleInput(100)" />
2.事件传值 通过标签自定义属性的方式 和 value
<input bindinput="handleInput" data-item="100" />
//或者
<input bindinput="handleInput" data-num="1" data-name="哈哈哈" />
handleTap(e){
console.log('事件传参:',e);
console.log('获取参数:',e.target.dataset);
console.log('获取参数二种方式:',e.currentTarget.dataset);
}
效果:
6.自定义组件
1. 定义组件
1.定义组件
2.在需要引入组件的页面的json文件中配置:
{
"usingComponents": {
//newCom 为定义的组件名
"newCom":"/components/newCom/newCom"
}
}
3.在页面中引入自定义组件
<!--index.wxml-->
<!-- 自定义组件 -->
<newCom></newCom>
2.组件父子传参
//父组件
<newCom count="{{num}}"></newCom>
//子组件js
// components/newCom/newCom.js
Component({
/**
* 组件的属性列表
*/
properties: {
// 父组件传值子组件
// 子组件在properties中接收参数
count:{
// 类型
type:Number,
// 默认值
value:0
}
}
})
//子组件wxml文件
<view>
<view> ====================== </view>
<view>
{{count}}
</view>
<view> ====================== </view>
</view>
3.组件子父传参
通过自定义事件传参
//子组件wxml
<view>
<view bindtap="toParams"> ====================== </view>
<view> ====================== </view>
</view>
//子组件js文件
// components/newCom/newCom.js
Component({
/**
* 组件的初始数据
*/
data: {
str:'我是值'
},
/**
* 组件的方法列表
*/
methods: {
// 子传父的方法写在这里
toParams(){
// 触发父页面的自定义事件
//this.triggerEvent();
console.log('发送'+this.data.str);
this.triggerEvent('tofu',this.data.str);
}
}
})
tips:组件的函数方法需要写在methods中
//父组件
//定义事件
<newCom bindtofu="getParams"></newCom>
Page({
getParams(e){
// 接收到子传父的值
console.log(e);
console.log('接收到子传父的值:' + e.detail);
}
})
效果:
7.路由
//路由获取
console.log(this.route)
若是组件中获取,能通过该种方式获取:const pages = getCurrentPages() ???
8.路由跳转
下列几个路由跳转方法都是异步方法,带参只能通过query方式
- wx.switchTab(Object object):跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面,不能带参数
- wx.reLaunch(Object object):关闭所有页面,打开到应用内的某个页面,路径后可以带参数。
- wx.redirectTo(Object object):关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面,路径后可以带参数
- wx.navigateTo(Object object):保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。路径后可以带参数。使用 wx.navigateBack 可以返回到原页面。小程序中页面栈最多十层,有events属性
- wx.navigateBack(Object object):关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages 获取当前的页面栈,决定需要返回几层。有delta(返回的页面数,如果 delta 大于现有页面数,则返回到首页)属性
tips:注意不同路由跳转方式与页面生命周期之间的关联 ,如想要执行onLoad中的方法,可以先关闭(wx.reLaunch)onLoad所在页面
9.页面间通信
如果一个页面由另一个页面通过 wx.navigateTo
打开,这两个页面间将建立一条数据通道:
这两个 EventChannel
对象间可以使用 emit
和 on
方法相互发送、监听事件
- 被打开的页面可以通过
this.getOpenerEventChannel()
方法来获得一个EventChannel
对象;wx.navigateTo
的success
回调中也包含一个EventChannel
对象。
1.当前页面向目标页面传递数据
//父级(当前)页面
Page({
data: {
parentData: {
id:'',
name: ''
},
},
onEventChannel() {
const parentData = this.data.parentData;
wx.navigateTo({
url: '/pages/detail/detail', // 打开的目标页面
success: (res) => {
// 通过eventChannel向被打开页面传送数据,目标页面是detail
res.eventChannel.emit('parentEmit', { data: parentData });
},
});
},
});
目标页面接收当前页面传递的数据:
在目标打开页面中通过getOpenerEventChange
方法,用on
进行监听被跳转页面的方法,就可以拿到被跳转页面中通过emit
方法传递过来的数据。
//子级(目标)页面
Page({
data: {
acceptData: {},
},
onLoad: function(options) {
// 通过getOpenerEventChannel对象,对parentEmit进行监听
const eventChannel = this.getOpenerEventChannel();
eventChannel.on('parentEmit', (data) => {
this.setData({
acceptData: data,
});
});
},
});
2. 目标页面向当前页面传递数据
//父级(当前)页面
Page({
data: {
parentData: {
name: ''
},
sonDetail: {}
},
onEventChannel() {
const parentData = this.data.parentData;
wx.navigateTo({
url: '/pages/detail/detail',
events: {
// 页面间通信接口,用于监听被打开页面发送到当前页面的数据
// 取被打开页面传送到当前页面的数据
sonPageEmit: (data) => {
console.log(data);
this.setData({
sonDetail: data
});
},
},
});
},
});
//子级(目标)页面
Page({
data: {
detailData: {}
},
onLoad: function() {
this.sonPagePrev();
},
sonPagePrev() {
const detailData= this.data.detailData;
const eventChannel = this.getOpenerEventChannel();
// 通过emit的方式进行触发,将子页面/目标页面中的数据传递给当前页面
eventChannel.emit('sonPageEmit', { data: detailData });
},
});
tips:除此之外,还有其他几种页面间通信的方式
1.路由跳转方法带参: wx.reLaunch,wx.redirectTo,wx.navigateTo;当传参有特殊字符时将对象转化为字符串后(JSON.stringify()
),然后使用encodeURIComponent
进行编码,然后在下个页面先用decodeURIComponent
进行解码
2.通过页面栈修改上级页面的数据
const pages = getCurrentPages(); // 可以获取当前页面栈,是一个数组
const prevPage = pages[pages.length - 2]; // 获取上个页面
prevPage.onLoad(); //调用上一个页面的方法
//修改上一个页面的data
//相当于子页面向父页面传参
prevPage.setData({
name: 'xxx',
});
3.通过在页面中获取getApp().globalData来更新和赋值多页面的数据,以达到页面间通信的目的
4.使用小程序本地缓存来达到页面间通信的目的
- 1.wx.setStorageSync(string key, any data)
- 2.wx.getStorageSync(string key)
- 3.wx.setStorage(Object object)
- 4.wx.getStorage(Object object)
10.生命周期
1.应用生命周期
属性 | 类型 | 说明 |
onLaunch | function | 监听小程序初始化 |
onShow | function | 监听小程序启动或切前台 |
onHide | function | 监听小程序切后台 |
onError | function | 错误监听函数 |
onPageNotFound | function | 页面不存在监听函数 |
使用场景??
2.页面生命周期
属性 | 类型 | 说明 |
---|---|---|
data | Object | 页面的初始数据 |
onLoad | function | 生命周期回调—监听页面加载 |
onShow | function | 生命周期回调—监听页面显示 |
onReady | function | 生命周期回调—监听页面初次渲染完成 |
onHide | function | 生命周期回调—监听页面隐藏 |
onUnload | function | 生命周期回调—监听页面卸载 |
onPullDownRefresh | function | 监听用户下拉动作 |
onReachBottom | function | 页面上拉触底事件的处理函数 |
onShareAppMessage | function | 用户点击右上角转发 |
onPageScroll | function | 页面滚动触发事件的处理函数 |
onResize | function | 页面尺寸改变时触发,详见 响应显示区域变化 |
onTabItemTap | function | 当前是 tab 页时,点击 tab 时触发 |
使用场景??
图示:
3.组件属性与生命周期
Component
构造器可用于定义组件,调用Component
构造器时可以指定组件的属性、数据、方法等
定义段 | 类型 | 是否必填 | 描述 |
---|---|---|---|
properties | Object Map | 否 | 组件的对外属性,是属性名到属性设置的映射表,参见下文 |
data | Object | 否 | 组件的内部数据,和 properties 一同用于组件的模板渲染 |
observers | Object | 否 | 组件数据字段监听器,用于监听 properties 和 data 的变化,参见 数据监听器 |
methods | Object | 否 | 组件的方法,包括事件响应函数和任意的自定义方法,关于事件响应函数的使用,参见 组件事件 |
created | Function | 否 | 组件生命周期函数,在组件实例刚刚被创建时执行,注意此时不能调用 setData ,参见 组件生命周期 |
attached | Function | 否 | 组件生命周期函数,在组件实例进入页面节点树时执行,参见 组件生命周期 |
ready | Function | 否 | 组件生命周期函数,在组件布局完成后执行,参见 组件生命周期 |
moved | Function | 否 | 组件生命周期函数,在组件实例被移动到节点树另一个位置时执行,参见 组件生命周期 |
detached | Function | 否 | 组件生命周期函数,在组件实例被从页面节点树移除时执行,参见 组件生命周期 |
11.分包
小程序要求单包(包括分包后)体积不能超过2M,分包后所有包体积不能超过16M,并且分包加载内容,可以提高性能
字段 | 类型 | 说明 |
---|---|---|
root | String | 分包根目录 |
name | String | 分包别名,分包预下载时可以使用 |
pages | StringArray | 分包页面路径,相对与分包根目录 |
independent | Boolean | 分包是否是独立分包 |
1.常规分包
通过在app.js中声明subpackages字段来进行分包
特征:
- 加载小程序时先加载主包,当需要访问分包的页面才加载分包内容
- 分包的页面可以访问主包的文件,数据,图片资源等
- 主包:分包之外的内容会被打包到主包中
- 主包中通常放置启动页/tabbar页面
示例:
此处划分为两个包:songPackage / activityPackage
"subpackages":[
{
"name": "songPackage",
"root": "songPackage",
"pages": [
"pages/recommend-song/recommend-song",
"pages/song-play/song-play"
]
},
{
"root": "activityPackage",
"pages": [
"pages/activity/activity"
]
}
]
目录示意:
2.独立分包
当分包设置关键字independent: true时,该分包为独立分包
特征:
- 独立分包只能访问本分包中的内容,不需要下载主包
- 独立分包不能依赖主包或其他包的内容
使用场景:
通常某些页面和当前小程序的其他页面关联不大的时候可进行独立分包 ,如:临时加的广告页 / 活动页
示例:
"subpackages":[
{
"name": "songPackage",
"root": "songPackage",
"pages": [
"pages/recommend-song/recommend-song",
"pages/song-play/song-play"
]
},
{
"root": "activityPackage",
"pages": [
"pages/activity/activity"
],
//声明activityPackage为独立分包
"independent": true
}
],
3.分包预下载
在配置有分包的情况下,在app.js中声明preloadRule 选项
声明格式:
key(页面路径): {packages: [预下载的包名 || 预下载的包的根路径])}
特征:
- 在加载当前包的时候可以设置预下载其他的包
- 缩短用户等待时间,提高用户体验
示例:
"subpackages":[
{
"name": "songPackage",
"root": "songPackage",
"pages": [
"pages/recommend-song/recommend-song",
"pages/song-play/song-play"
]
},
{
"root": "activityPackage",
"pages": [
"pages/activity/activity"
],
"independent": true
}
],
//声明分包预下载
"preloadRule":{
//加载pages/index/index对应页面时,预下载songPackage分包的内容
"pages/index/index": {
"network": "all",
"packages":["songPackage"]
}
}
12.引入npm包管理
1.在小程序项目根目录下进行 npm init -y 初始化,生成包管理配置文件
如下图:
2.在微信开发者工具勾选----》本地设置 ----》使用npm模块
3.下包
4.每次下完包后都需要在微信开发者工具勾选----》工具(菜单选项)-----》构建npm
5.勾选后会将node_modules中的包打包到miniprogram_npm中
tips:实际上,小程序使用的并不是node_modules中的包,而是二次打包后(构建npm)的miniprogram_npm中的包
npm资源:
npm中提供了很多的微信小程序轮子 :https://www.npmjs.com/search?q=miniprogram
以下载pubsub.js包为:https://github.com/mroderick/PubSubJS
npm install pubsub-js
//引入
import PubSub from 'pubsub-js';
实现跨页面通信
// 点击切歌的回调
handleSwitch(e){
const type = e.currentTarget.id;
// 关闭当前播放的音乐
this.backgroundAudioManager.stop();
// 发布消息数据给recommend-song页面
PubSub.publish('switchType',type);
// 订阅recommend-song页面的消息数据
PubSub.subscribe('musicId',(msg,data) => {
console.log('musicId:',data);
this.getMusicInfo(data);
this.musicController(true, data);
//取消订阅,订阅会一直累加
PubSub.unsubscribe('musicId');
});
}
4.小程序文档阅读了解
1.宿主环境
微信客户端为小程序的宿主环境,小程序借助宿主环境的能力完成一些普通网页不能完成的功能
2.运行环境
小程序运行环境分为渲染层和逻辑层,其中 WXML 模板和 WXSS 样式工作在渲染层,JS 脚本工作在逻辑层。
小程序的渲染层和逻辑层分别由2个线程管理:渲染层的界面使用了WebView 进行渲染;逻辑层采用JsCore线程运行JS脚本。一个小程序存在多个界面,所以渲染层存在多个WebView线程,这两个线程的通信会经由微信客户端(下文中也会采用Native来代指微信客户端)做中转,逻辑层发送网络请求也经由Native转发
3.sitemap配置
小程序根目录下的sitemap用来配置小程序及其页面是否允许被微信索引
4.场景值
场景值用来描述用户进入小程序的路径
由于Android系统限制,目前还无法获取到按 Home 键退出到桌面,然后从桌面再次进小程序的场景值,对于这种情况,会保留上一次的场景值
获取场景值:
小程序获取:App
的 onLaunch(的形参)
和 onShow(的形参)
,或wx.getLaunchOptionsSync
场景值一般使用场景:日志追踪,切换页面显示等等
5.注册页面
简单的页面使用Page({})来构造,复杂的页面可以使用Component构造器来构造。
6.wxs
是微信小程序独有的script,全称是weixin script,在ios上性能更好。
wxs代码可以编写在 wxml 文件中的 <wxs>
标签内,或以 .wxs
为后缀名的文件内。
tips:wxs有自己的语法,语法和ES5类似。
代码示例:
//utils/filters.wxs
//语法格式与ES5相似
var format = function(text){
return text;
}
module.exports = {
format: format
};
<view class="container">
活动页,测试独立分包
<text>{{ filters.format('aaaa')}}</text>
</view>
<!-- 外部引入wxs -->
<wxs src="../../utils/filters.wxs" module="filters" ></wxs>
7.简易双向绑定
8. 小程序运行机制
1.前 / 后台状态
小程序启动后,界面被展示给用户,此时小程序处于前台状态。
当用户点击右上角胶囊按钮关闭小程序,或者按了设备 Home 键离开微信时,小程序并没有完全终止运行,而是进入了后台状态,小程序还可以运行一小段时间。
当用户再次进入微信或再次打开小程序,小程序又会从后台进入前台。但如果用户很久没有再进入小程序,或者系统资源紧张,小程序可能被销毁,即完全终止运行。
2.小程序启动
小程序启动可以分为两种情况,一种是冷启动,一种是热启动。
- 冷启动:如果用户首次打开,或小程序销毁后被用户再次打开,此时小程序需要重新加载启动,即冷启动。
- 热启动:如果用户已经打开过某小程序,然后在一定时间内再次打开该小程序,此时小程序并未被销毁,只是从后台状态进入前台状态,这个过程就是热启动。
3.小程序销毁时机
只有当小程序进入后台一定时间,或者系统资源占用过高,才会被销毁。具体而言包括以下几种情形:
- 当小程序进入后台,可以维持一小段时间的运行状态,如果这段时间内都未进入前台,小程序会被销毁。
- 当小程序占用系统资源过高,可能会被系统销毁或被微信客户端主动回收。
- 在 iOS 上,当微信客户端在一定时间间隔内连续收到系统内存告警时,会根据一定的策略,主动销毁小程序,并提示用户 「运行内存不足,请重新打开该小程序」。具体策略会持续进行调整优化。
- 建议小程序在必要时使用 wx.onMemoryWarning 监听内存告警事件,进行必要的内存清理。
4.小程序更新机制
小程序每次冷启动时,都会检查是否有更新版本,如果发现有新版本,将会异步下载新版本的代码包,并同时用客户端本地的包进行启动,即新版本的小程序需要等下一次冷启动才会应用上。
如果需要马上应用最新版本,可以使用 wx.getUpdateManager API 进行处理
const updateManager = wx.getUpdateManager()
updateManager.onCheckForUpdate(function (res) {
// 请求完新版本信息的回调
console.log(res.hasUpdate)
})
updateManager.onUpdateReady(function () {
wx.showModal({
title: '更新提示',
content: '新版本已经准备好,是否重启应用?',
success(res) {
if (res.confirm) {
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
updateManager.applyUpdate()
}
}
})
})
updateManager.onUpdateFailed(function () {
// 新版本下载失败
})
9.自定义组件
1.slot
- <slot></slot> --可用于在自定义组件中插入外部内容,属性key:name 类似于vue的插槽
多个slot时,需要在组件js中声明启用:
Component({
options: {
multipleSlots: true // 在组件定义时的选项中启用多slot支持
}
})
2.使用Component构造器构造页面
小程序的页面也可以视为自定义组件。因而,页面也可以使用 Component
构造器构造,拥有与普通组件一样的定义段与实例方法。但此时要求对应 json 文件中包含 usingComponents
定义段。
此时,组件的属性可以用于接收页面的参数,如访问页面 /pages/index/index?paramA=123¶mB=xyz
,如果声明有属性 paramA
或 paramB
,则它们会被赋值为 123
或 xyz
。
页面的生命周期方法(即 on
开头的方法),应写在 methods
定义段中
3.获取组件实例
可在父组件里调用 this.selectComponent
,获取子组件的实例对象。
调用时需要传入一个匹配选择器 selector
,如:this.selectComponent(".my-component")
// 父组件
Page({
data: {},
getChildComponent: function () {
const child = this.selectComponent('.my-component');
console.log(child)
}
})
在上例中,父组件将会获取 class
为 my-component
的子组件实例对象,即子组件的 this
4.组件生命周期
组件的生命周期,指的是组件自身的一些函数,这些函数在特殊的时间点或遇到一些特殊的框架事件时被自动触发。
其中,最重要的生命周期是 created
attached
detached
,包含一个组件实例生命流程的最主要时间点。
- 组件实例刚刚被创建好时,
created
生命周期被触发。此时,组件数据this.data
就是在Component
构造器中定义的数据data
。 此时还不能调用setData
。 通常情况下,这个生命周期只应该用于给组件this
添加一些自定义属性字段。- 在组件完全初始化完毕、进入页面节点树后,
attached
生命周期被触发。此时,this.data
已被初始化为组件的当前值。这个生命周期很有用,绝大多数初始化工作可以在这个时机进行。- 在组件离开页面节点树后,
detached
生命周期被触发。退出一个页面时,如果组件还在页面节点树中,则detached
会被触发。
定义生命周期的方法
生命周期方法可以直接定义在 Component
构造器的第一级参数中。
自小程序基础库版本 2.2.3 起,组件的的生命周期也可以在 lifetimes
字段内进行声明(这是推荐的方式,其优先级最高)
Component({
lifetimes: {
attached: function() {
// 在组件实例进入页面节点树时执行
},
detached: function() {
// 在组件实例被从页面节点树移除时执行
},
},
// 以下是旧式的定义方式,可以保持对 <2.2.3 版本基础库的兼容
attached: function() {
// 在组件实例进入页面节点树时执行
},
detached: function() {
// 在组件实例被从页面节点树移除时执行
},
// ...
})
在 behaviors 中也可以编写生命周期方法,同时不会与其他 behaviors 中的同名生命周期相互覆盖。但要注意,如果一个组件多次直接或间接引用同一个 behavior ,这个 behavior 中的生命周期函数在一个执行时机内只会执行一次
组件所在页面的生命周期
使用场景:组件所在页面钩子函数触发时,组件需要进行变动
还有一些特殊的生命周期,它们并非与组件有很强的关联,但有时组件需要获知,以便组件内部处理。这样的生命周期称为“组件所在页面的生命周期”,在 pageLifetimes
定义段中定义。其中可用的生命周期包括:
生命周期 | 参数 | 描述 | 最低版本 |
---|---|---|---|
show | 无 | 组件所在的页面被展示时执行 | 2.2.3 |
hide | 无 | 组件所在的页面被隐藏时执行 | 2.2.3 |
resize | Object Size | 组件所在的页面尺寸变化时执行 | 2.4.0 |
Component({
pageLifetimes: {
show: function() {
// 页面被展示
},
hide: function() {
// 页面被隐藏
},
resize: function(size) {
// 页面尺寸变化
}
}
})
5.behaviors
behaviors
是用于组件间代码(页面中也可使用)共享的特性,类似于一些编程语言中的 “mixins” 或 “traits”。
每个 behavior
可以包含一组属性、数据、生命周期函数和方法。组件引用它时,它的属性、数据和方法会被合并到组件中,生命周期函数也会在对应时机被调用。 每个组件可以引用多个 behavior
,behavior
也可以引用其它 behavior
执行优先级:behaviors优先级
优先级总结:
属性,数据字段,方法,生命周期:behaviors > Component
小程序有提供内置hehaviors,暂不知如何使用
代码示例:
//抽象组件的公共行为,类似vue的mixin
let behavior = Behavior({
properties:{
img: String,
content: String,
},
data:{
},
methods:{
}
});
export {
behavior
}
引入组件中使用:
// activityPackage/components/test.js
import { behavior } from '../pages/activity/behavior';
Component({
behaviors:[ behavior ],
/**
* 组件的属性列表
*/
properties: {
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
}
})
6.数据监听器(observers)
数据监听器可以用于监听和响应组件中任何属性和数据字段的变化
//小程序示例
Component({
attached: function() {
this.setData({
numberA: 1,
numberB: 2,
})
},
observers: {
'numberA, numberB': function(numberA, numberB) {
// 在 numberA 或者 numberB 被设置时,执行这个函数
this.setData({
sum: numberA + numberB
})
}
}
})
属性也有单独的observer,只用于监听该属性,数据监听器比属性observer更强大且通常具有更好的性能。
代码示例:
Component({
properties: {
index:{
type:Number,
observer: function(newVal,oldVal,changedPath){
let val = newVal < 10 ? '0' + newVal : newVal;
}
}
}
})
tips:两者都需谨慎使用setData({}),易引起死循环。
7.纯数据字段
纯数据字段是一些不用于界面渲染的 data 字段,可以用于提升页面更新性能
组件数据中的纯数据字段
有些情况下,某些 data
中的字段(包括 setData
设置的字段)既不会展示在界面上,也不会传递给其他组件,仅仅在当前组件内部使用。
此时,可以指定这样的数据字段为“纯数据字段”,它们将仅仅被记录在 this.data
中,而不参与任何界面渲染过程,这样有助于提升页面更新性能。
指定“纯数据字段”的方法是在 Component
构造器的 options
定义段中指定 pureDataPattern
为一个正则表达式,字段名符合这个正则表达式的字段将成为纯数据字段。
Component({
options: {
pureDataPattern: /^_/ // 指定所有 _ 开头的数据字段为纯数据字段
}
})
tips:可以视作一种规范
小程序真的蛮难的,而且东西很多