首页 > 热点 > 微信 > 正文

在微信小程序里使用watch和computed的方法

2024-07-22 01:17:29
字体:
来源:转载
供稿:网友

在开发 vue 的时候,我们可以使用 watch 和 computed 很方便的检测数据的变化,从而做出相应的改变,但是在小程序里,只能在数据改变时手动触发 this.setData() ,那么如何给小程序也加上这两个功能呢?

我们知道在 vue 里是通过 Object.defineProperty 来实现数据变化检测的,给该变量的 setter 里注入所有的绑定操作,就可以在该变量变化时带动其它数据的变化。那么是不是可以把这种方法运用在小程序上呢?

实际上,在小程序里实现要比 vue 里简单,应为对于 data 里对象来说,vue 要递归的绑定对象里的每一个变量,使之响应式化。但是在微信小程序里,不管是对于对象还是基本类型,只能通过 this.setData() 来改变,这样我们只需检测 data 里面的 key 值的变化,而不用检测 key 值里面的 key 。

先上测试代码

<view>{{ test.a }}</view><view>{{ test1 }}</view><view>{{ test2 }}</view><view>{{ test3 }}</view><button bindtap="changeTest">change</button>
const { watch, computed } = require('./vuefy.js')Page({ data: {  test: { a: 123 },  test1: 'test1', }, onLoad() {  computed(this, {   test2: function() {    return this.data.test.a + '2222222'   },   test3: function() {    return this.data.test.a + '3333333'   }  })  watch(this, {   test: function(newVal) {    console.log('invoke watch')    this.setData({ test1: newVal.a + '11111111' })   }  }) }, changeTest() {  this.setData({ test: { a: Math.random().toFixed(5) } }) },})

现在我们要实现 watch 和 computed 方法,使得 test 变化时,test1、test2、test3 也变化,为此,我们增加了一个按钮,当点击这个按钮时,test 会改变。

watch 方法相对简单点,首先我们定义一个函数来检测变化:

function defineReactive(data, key, val, fn) { Object.defineProperty(data, key, {  configurable: true,  enumerable: true,  get: function() {   return val  },  set: function(newVal) {   if (newVal === val) return   fn && fn(newVal)   val = newVal  }, })}

然后遍历 watch 函数传入的对象,给每个键调用该方法

function watch(ctx, obj) { Object.keys(obj).forEach(key => {  defineReactive(ctx.data, key, ctx.data[key], function(value) {   obj[key].call(ctx, value)  }) })}

这里有参数是 fn ,即上面 watch 方法里 test 的值,这里把该方法包一层,绑定 context。

接着来看 computed,这个稍微复杂,因为我们无法得知 computed 里依赖的是 data 里面的哪个变量,因此只能遍历 data 里的每一个变量。

function computed(ctx, obj) { let keys = Object.keys(obj) let dataKeys = Object.keys(ctx.data) dataKeys.forEach(dataKey => {  defineReactive(ctx.data, dataKey, ctx.data[dataKey]) }) let firstComputedObj = keys.reduce((prev, next) => {  ctx.data.$target = function() {   ctx.setData({ [next]: obj[next].call(ctx) })  }  prev[next] = obj[next].call(ctx)  ctx.data.$target = null  return prev }, {}) ctx.setData(firstComputedObj)}            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表