小程序技能進階回憶錄 - 自主實現數據偵聽器和計算器

告訴元首我已盡力,告訴父親我仍然愛他!

熟悉 Vue 的同窗對 computedwatch 必定很熟悉,這些特性大大方便了咱們對代碼中的數據進行處理:html

var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  computed: {
    // 計算屬性的 getter
    reversedMessage: function () {
      // `this` 指向 vm 實例
      return this.message.split('').reverse().join('')
    }
  }
})
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar',
    fullName: 'Foo Bar'
  },
  watch: {
    firstName: function (val) {
      this.fullName = val + ' ' + this.lastName
    },
    lastName: function (val) {
      this.fullName = this.firstName + ' ' + val
    }
  }
})

這是 Vue 官網中兩段代碼。git

官方實現

現在小程序也有了本身的實現,詳見官方文檔 observer 。小程序官方 github
中也開源了經過 Behaviors 實現的 Vue 風格的computedwatchhttps://github.com/wechat-miniprogram/computedgithub

那麼在微信沒有提供這些方法以前,如何自主實現數據的偵聽器和計算屬性呢?小程序

## 自主實現緩存

先看看定義的使用文檔:微信

Page({
 data: {
   list: [],
   list2: [],
   size: 0
 },
 // 偵聽器函數名必須跟須要被偵聽的 data 對象中的屬性同名,
 // 其參數中的 newValue 爲屬性改變後的新值,oldValue 爲改變前的舊值
 watch: {
   // 若是 `list` 發生改變,這個函數就會運行
   list(newValue, oldValue) {
     console.log(oldValue + '=>' + newValue)
   }
 },
 // 傳入的參數list必須是 data 裏面的屬性
 // 這裏能夠傳入多個 data 屬性
 computed({
   list,
   list2
 }) {
   return {
     size: list.length,
     size2: list2.length
   }
 }
})

Page 的傳參中多了兩個熟悉的屬性,用法不用解釋太多。須要繼續對小程序提供的 Page 方法進行改造,此外,由於全部數據變化都會用到 setData 方法去觸發,因此還須要改造這個方法。app

改造 Page 和 setData

想要基於原有的 setData 進行封裝,那就得先獲得這個函數緩存下來(像是緩存原有的 Page 同樣)。想到 onLoad 是小程序頁面的第一個生命週期函數,能夠在這裏進行操做:函數

// 緩存原有的 `Page`
let originPage = Page

// 定義新的 Page
function MyPage(config) {
  let that = this
  this.watch = config.watch
  this.computed = config.computed
  this.lifetimeBackup = {
    onLoad: config.onLoad
  }
  config.onLoad = function(options) {
    // 緩存下原有的 `setData`
    this._setData = this.setData.bind(this)
    this.setData = (data) => {
      // 偵聽器
      that.watching(data)
      // 計算器
      let newData = that.getComputedData(data)
      this._setData(extend(data, newData))
    }
    // 備份下頁面實例
    that.context = this
    // 執行真正的 `onLoad`
    this.lifetimeBackup.onLoad.call(this, options)
  }
  
  // ...

  originPage(config)
}

MyPage.prototype.watching = funtion(data) {
  // 執行偵聽器
  // ...
}

// 計算器
MyPage.prototype.getComputedData = function(data) {
  // 開始生成新的數據
  // ...
}

function page (config) {
  return new MyPage(config)
}

大體代碼如上,從新定義了 this.setData,備份了原有的 setDatathis._setData。固然,這裏只考慮了 setData 傳一個參數的狀況,多個參數須要再對代碼優化下。優化

注意:調用 watchingcreateNewData 的對象是 that,由於 this 指向小程序頁面實例,沒有自定的這個方法。this

作完上述改造,後續的 watchcomputed 就簡單多了。

偵聽器 watch

MyPage.prototype.watching = function(data) {
  var context = this.context
  var oldData = context.data
  // 開始生成新的數據
  var watch = this.watch
  if (watch) {
    Object.keys(watch).forEach(function (k) {
      // 若是新的 data 中屬性被偵聽,執行偵聽函數
      if (k in data) {
        var newValue = data[k]
        var oldValue = oldData[k]
        watch[k].apply(context, [
          newValue,
          oldValue
        ])
      }
    })
  }
}

簡易的偵聽器就寫好了,經過 setData 觸發自定的 watch 中的偵聽函數。

計算器 computed

MyPage.prototype.getComputedData = function(data) {
  var context = this.context
  var computed = this.computed
  var computedData
  if (computed) {
    computedData = computed.call(context, data)
  }
  return computedData
}

這樣就獲得了計算後的新生成的數據:computedData

總結

不斷的經過備份、代理微信原有的方法,自主實現了簡單的偵聽器和計算器。固然這些代碼只是爲了方便分享提取出來了提供思路,實際業務中遇到狀況複雜的多,代碼量遠遠也不止這些。

相關文章
相關標籤/搜索