背景

既然小程序的组件已经有Observer功能,那为什么还要手写watch功能呢?

  1. Observer只能在Component中使用,没法在Page中使用。若是想在Page中监控某一数据的变化,Observer做不到。
  2. Observer属于小程序的新功能,只能在高版本微信使用,低版本微信无法使用。公司的小程序就因为使用了Observer功能,导致很多低版本微信用户无法使用这个小程序。

实现

新建一个watch.js文件,代码如下

function watch(key, callback) {
  // 先执行一次watch
  callback.call(this, this.data[key])
  let that = this
  let tmpData = this.data[key]
  Object.defineProperty(this.data, key, {
    set: function(value) {
      tmpData = value
      // 值变化了再执行一次
      callback.call(that, value)
    },
    get: function() {
      return tmpData
    }
  })
}
export default watch

原理很简单,就是使用Object.defineProperty来定义要侦听的数据对象,当该值变化时,会执行其中的set方法,我们在set方法中执行侦听器回调就可以了。注:因为组件初始化的时候不会执行set方法,所以需要额外在开始的时候执行一次回调。

这个方法可以在Component的attached、ready函数中或者page的onShow、onLoad函数中使用。

Component中使用watch功能示例如下,Page中用法类似

import watch from '../../utils/watch.js'
Component({
  properties: {
    showPercent: {
      type: Boolean,
      value: true
    },
    percents: Array
  },
  attached: function() {
    watch.call(this, 'percents', function (val) {
      if (val && val.length >0) {
        this.setData({
          showPercent: true
        })
      } else {
        this.setData({
          showPercent: false
        })
      }
    })
  }
})

为了保证watch函数中的this指向,必须使用watch.call(this, ...arguments)的方式调用watch方法。这其中,第一个参数,this,固定写法;第二个参,数要watch的参数名;第三个参数,数值改变后执行的函数。

结语

实现了该watch方法,就可以解决开头说的两个问题了

  1. 在Page中使用侦听器
  2. 兼容低版本微信用户

下一篇《微信小程序实现数据侦听器watch,包含子属性的watch》有方案更高级、使用更简单、且支持子属性watch的实现方法。