アプレットでウォッチを実現

3222 ワード

WeChatアプレットの公式はwatchを提供していません.dataの中の属性の変化をモニターします.
日常開発でウォッチがなくなったら、手足を縛るようになります.
ES 5は、Object.defineProperty()の方法を提供し、getter/setterハイジャックオブジェクトを通じて、賦課時にsetterメソッドを呼び出し、watchで対応する方法を実行することにより、傍受を実現する.
傍受者を設定する
setWatch関数は、dataのすべての属性を巡回します.一つの属性がないためにモニターを追加します.
const setWatcher = (page) => {
  const data = page.data
  const watch = page.watch
  Object.keys(watch).forEach(key => {
    let targetData = data
    const targetKey = key
    const watchFun = watch[key].handler || watch[key]
    const deep = watch[key].deep
    observe(targetData, targetKey, watchFun, deep, page)
  })
}
モニターを実現
observe関数は5つのパラメータを受信します.
  • pagaのdata
  • data中の属性key
  • watchの関数
  • は、dataの属性を深度傍受するかどうか
  • .
  • pageは、傍受関数
  • に伝達される.
    deepがtrueであれば、深度傍受が必要となり、再帰的にobserveを呼び出し、深度傍受を実現する.
    Object.definePropertyのsetter方法を使って、外部のdataデータに対する処理をブロックし、同時にwatFnを呼び出して傍受を実現します.
    watch Fnは二つのパラメータを受け取り、valueとoldValueはcallを使ってpageを伝えます.watchの中で正常にpage(this)を使うことができます.
    /**
     * 
     * @param {Object} obj  // data
     * @param {String} key  // data   
     * @param {Fucntion} watchFun  //     
     * @param {Boolean} deep //       
     * @param {Object} page  // page 
     */
    const observe = (obj, key, watchFn, deep, page) => {
      let oldVal = obj[key]
      if (oldVal !== null && typeof oldVal === 'object' && deep) {
        Object.keys(oldVal).forEach(item => {
          observe(oldVal, item, watchFun, deep, page)
        })
      }
      Object.defineProperty(obj, key, {
        configurable: true,
        enumerable: true,
        set(value) {
          if (value === oldVal) return
          watchFn.call(page, value, oldVal)
          oldVal = value
        },
        get() {
          return oldVal
        }
      })
    }
    注意事項:
  • watchは既に存在している属性のみをモニターすることができ、配列のpop()やpush()などの方法はトリガされません.
  • 最初はdataの属性ではなく、後続の動的に追加された属性もトリガされない.
    完全コード
    const observe = (obj, key, watchFun, deep, page) => {
      let oldVal = obj[key]
      if (oldVal !== null && typeof oldVal === 'object' && deep) {
        Object.keys(oldVal).forEach(item => {
          observe(oldVal, item, watchFun, deep, page)
        })
      }
      Object.defineProperty(obj, key, {
        configurable: true,
        enumerable: true,
        set(value: any) {
          if (value === oldVal) return
          watchFun.call(page, value, oldVal)
          oldVal = value
        },
        get() {
          return oldVal
        }
      })
    }
    
    export const setWatcher = (page) => {
      const data = page.data
      const watch = page.watch
      Object.keys(watch).forEach(key => {
        let targetData = data
        const targetKey = key
        const watchFun = watch[key].handler || watch[key]
        const deep = watch[key].deep
        observe(targetData, targetKey, watchFun, deep, page)
      })
    }
    使用
    import {  setWatcher} from "/utils/watch.js"
    
    Page({
      data: {
        age: 12,
          person: {
            name: 'uccs'
          }
      },
      onLoad() {
        setWatcher(this)
      },
      watch: {
        age(val) {
          console.log(val)
        },
        person: {
          deep: true,
          handler(val) {
            console.log(val)
          }
        }
      },
      onClick() {
        this.data.age = 18
        this.data.person.name = 'tiantian'
      }
    })