1. 程式人生 > >初探Vue原理之view-model的資料動態雙向繫結

初探Vue原理之view-model的資料動態雙向繫結

Vue應用的是mvvm框架,view和model分離,然後通過vm雙向資料繫結,`

<!-- 模板 -->
<div id="app">
    {{msg}}
</div>
<!-模型->
// 原生物件即資料
var data = {
    msg: 'hello!'
}
// 建立一個 ViewModel 例項
var vm = new Vue({
    // 選擇目標元素
    el: '#app',
    // 提供初始資料
    data: data
})

然而一個動態資料的繫結,是怎麼實現的呢,首先Vue利用es5的defineProperty方法裡的get,set方法,進行資料的設定和獲取。

 Object.defineProperty(Vue.prototype, '$data', {
     get () {
      return this._data
     },
     set (newData) {
       if (newData !== this._data) {
         this._setData(newData)
       }
     }   })

從這段原始碼可以看出設定資料時會呼叫setData方法,而setData的實現如下

Vue.prototype._setData = function (newData) {
    newData = newData || {}
    var
oldData = this._data this._data = newData var keys, key, i // unproxy keys not present in new data keys = Object.keys(oldData) i = keys.length while (i--) { key = keys[i] if (!(key in newData)) { this._unproxy(key) } } // proxy keys not already proxied,
// and trigger change for changed values keys = Object.keys(newData) i = keys.length while (i--) { key = keys[i] if (!hasOwn(this, key)) { // new property this._proxy(key) } } oldData.__ob__.removeVm(this) observe(newData, this) this._digest() }

這段程式碼的後三行可知首先移除舊的資料,然後呼叫observe(newData, this);

export function observe (value, vm) {
  if (!value || typeof value !== 'object') {
    return
  }
  var ob
  if (
    hasOwn(value, '__ob__') &&
    value.__ob__ instanceof Observer
  ) {
    ob = value.__ob__
  } else if (
    shouldConvert &&
    (isArray(value) || isPlainObject(value)) &&
    Object.isExtensible(value) &&
    !value._isVue
  ) {
    ob = new Observer(value)
  }
  if (ob && vm) {
    ob.addVm(vm)
  }
  return ob

}
根據新的資料建立一個新的觀察物件,這裡提一下,vue用的是訂閱模式,首先會把每個資料訂閱一下,當資料變化時,會通知watcher重新計算值
最後一行程式碼this._digest()就是通知更新物件的值,把物件設定成newData,我理解的大概過程是這樣的,大家看到有錯誤理解的歡迎給我指出來。這裡提醒一下之前犯過的錯誤,例如:

<template>
  <p>{{user.sex}}</p>
</template>

Data(){
User:{}
}
Ready(){
This.user={name:’smx’,age:12};
This.user.sex=’女’;
}

這將在視圖裡面無法顯示,this.user是通過defineProperty裡set方法設定進去的,所以在後面再設定屬性的時候物件將不能跟蹤到該屬性