小程序自定义组件扩展 behavior,计算属性 computed 和监听器 watch 的实现。在 data 或者 properties 改变时,会重新计算 computed 字段并触发 watch 监听器。
此 behavior 依赖开发者工具的 npm 构建。具体详情可查阅官方 npm 文档。
注意: 4.0.0 大版本变更了最基本的接口名,从低版本升级到 4.0.0 以上时请注意 #60 的问题。
需要小程序基础库版本 >= 2.11.0 的环境。
可以直接体验一下这个代码片段,它包含了基本用法示例:https://developers.weixin.qq.com/s/4KYn6TmJ7osP
体验该代码片段前,需要先安装并构建相对应的 npm 包。
npm install --save miniprogram-computed// component.jsconstcomputedBehavior=require('miniprogram-computed').behaviorconstbehaviorTest=require('./behavior-test')// 引入自定义 behaviorComponent({behaviors: [behaviorTest,computedBehavior],data: {a: 1,b: 1,},computed: {sum(data){// 注意: computed 函数中不能访问 this ,只有 data 对象可供访问// 这个函数的返回值会被设置到 this.data.sum 字段中returndata.a+data.b+data.c// data.c 为自定义 behavior 数据段},},methods: {onTap(){this.setData({a: this.data.b,b: this.data.a+this.data.b,})},},})//behavior-test.jsmodule.exports=Behavior({data: {c: 2,},})<view>A = {{a}}</view>
<view>B = {{b}}</view>
<view>SUM = {{sum}}</view>
<buttonbindtap="onTap">click</button>constcomputedBehavior=require('miniprogram-computed').behaviorComponent({behaviors: [computedBehavior],data: {a: 1,b: 1,sum: 2,},watch: {'a, b': function(a,b,oldA,oldB){this.setData({sum: a+b,})},},methods: {onTap(){this.setData({a: this.data.b,b: this.data.a+this.data.b,})},},})<view>A = {{a}}</view>
<view>B = {{b}}</view>
<view>SUM = {{sum}}</view>
<buttonbindtap="onTap">click</button>使用 glass-easel Chaining API 时,可以用更友好的 computedwatch 函数。
import{computed,watch}from'miniprogram-computed'exportdefaultComponent().data(()=>({a: 1,b: 2,})).init((ctx)=>{constdata=computed(ctx,{c: (data)=>data.a+data.b,d: (data)=>data.a*2,},{e: (data)=>data.c+data.d,})watch(ctx,'a, b',(a: number,b: number)=>{// ...})}).register()由于通过 behavior 的方式引入不能获得类型支持, 因此为了获得类型的支持, 可以使用一个辅助组件构造器:
import{ComponentWithComputed}from'miniprogram-computed'ComponentWithComputed({data: {a: 1,b: 1,sum: 2,},watch: {'a, b': function(a,b){this.setData({sum: a+b,})},},computed: {sum(data){// 注意: computed 函数中不能访问 this ,只有 data 对象可供访问// 这个函数的返回值会被设置到 this.data.sum 字段中returndata.a+data.b+data.sum// data.c 为自定义 behavior 数据段},},})当使用该构造器的时候, 编译器可以给 computed 和 watch 提供自动提示和类型支持。
注意: 当使用该构造器的时候, 无需手动加入 computedBehavior , 该构造器会自动引入该 behavior 。
(类似地,也有 BehaviorWithComputed 构造器对应于 Bahavior 。)
关于 TS 兼容问题
若在小程序中用 TypeScript 进行开发并使用到了 Component 构造器。这时定义 computed 或 watch 字段会出现类型报错。
针对此问题,推荐使用 ComponentWithComputed 构造器代替 Component 构造器。
有一些辅助 API 用于控制 watch 时的一些行为表现。可以在 this 上访问到这些方法;使用 Chaining API 时, watch() 的返回值会带有这些方法。
| 方法名 | 参数示例 | 说明 |
|---|---|---|
| disableWatches | disableWatches() | 暂时禁用 watch |
| enableWatches | enableWatches(triggerNow) | 启用 watch ,如果 triggerNow 为真,立刻触发所有 watch |
| triggerAllWatches | triggerAllWatches() | 立刻触发所有 watch 一次 |
从原理上说, watch 的性能比 computed 更好;但 computed 的用法更简洁干净。
此外, computed 字段状态只能依赖于 data 和其他 computed 字段,不能访问 this 。如果不可避免要访问 this ,则必须使用 watch 代替。
- 无论字段是否真的改变,
observers都会被触发,而watch只在字段值改变了的时候触发,并且触发时带有参数。
在 watch 字段上可以使用 ** 通配符,它能够监听这个字段下的子字段的变化(类似于小程序基础库本身的 observers )。
constcomputedBehavior=require('miniprogram-computed').behaviorComponent({behaviors: [computedBehavior],data: {obj: {a: 1,b: 2,},},watch: {'obj.**': function(obj){this.setData({sum: obj.a+obj.b,})},},methods: {onTap(){this.setData({'obj.a': 10,})},},})除此以外:
- 对于没有使用
**通配符的字段,在watch检查值是否发生变化时,只会进行粗略的浅比较(使用===); - 对于使用了
**通配符的字段,则会进行深比较,来尝试精确检测对象是否真的发生了变化,这要求对象字段不能包含循环(类似于JSON.stringify)。