Vue數據響應式怎么做到的

如何追蹤變化

1. Object.defineProperty 把屬性轉為 getter/setter,用以檢測數據的變化。
  • 當把一個普通的 JavaScript 對象傳入 Vue 實例作為 data 選項,Vue 將遍歷此對象所有的 property,并使用 Object.defineProperty 把這些 property全部轉為 getter/setter。
  • get 是一個函數,當屬性被訪問時,會觸發(fā) get 函數
  • set 也是一個函數,當屬性被賦值時,會觸發(fā) set 函數,例如
var obj={    
    name:"響應式"
}
Object.defineProperty(obj,"name",{
    get(){        
        console.log("get 被觸發(fā)")
    },
    set(val){        
        console.log("set 被觸發(fā)")
    }
})
  • 當訪問 obj.name 時,會打印 ' get 被觸發(fā) '
  • 當給 obj.name 賦值時,obj.name = 'xxx',會打印 ' set 被觸發(fā) '
2. watcher ,把組件渲染接觸過的數據屬性記為依賴
  • 每個組件實例都對應一個 watcher 實例,它會在組件渲染的過程中把“接觸”過的數據 property 記錄為依賴。之后當依賴項的 setter 觸發(fā)時,會通知 watcher,從而使它關聯(lián)的組件重新渲染。

由于 JavaScript 的限制,Vue 不能檢測數組和對象的變化,解決方法是手動調用 Vue.set 或者 this.$set

1. 檢測對象的變化
  • 對于已經創(chuàng)建的實例,Vue 不允許動態(tài)添加根級別的響應式 property。
var vm = new Vue({
  data:{
    a:1
  }
})

// `vm.a` 是響應式的

vm.b = 2
// `vm.b` 是非響應式的
  • 使用 Vue.set或者vm.$set (object, propertyName, value) 方法向嵌套對象添加響應式屬性
Vue.set(vm.someObject, 'b', 2)   //Vue.set
this.$set(this.someObject,'b',2)    //vm.$set 實例方法,這也是全局 Vue.set 方法的別名
  • 有時可能需要為已有對象賦值多個新 property,比如使用 Object.assign() 或 _.extend()。但是,這樣添加到對象上的新 property 不會觸發(fā)更新。在這種情況下,你應該用原對象與要混合進去的對象的 property 一起創(chuàng)建一個新的對象。
// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
2. 檢測數組的變化
  • 當你利用索引直接設置一個數組項和修改數組的長度時,Vue 不能檢測到數組的變動:
  • 例如:
var vm = new Vue({
  data: {
    items: ['a', 'b', 'c']
  }
})
vm.items[1] = 'x' // 不是響應性的
vm.items.length = 2 // 不是響應性的
  • 利用索引直接設置一個數組項可以用對象的方式(Vue.set或者vm.$set (object, propertyName, value) ),也可以用splice方法
Vue.set(vm.items, indexOfItem, newValue) //Vue.set
vm.$set(vm.items, indexOfItem, newValue) //vm.$set
vm.items.splice(indexOfItem, 1, newValue) //splice
  • 修改數組的長度也可以用splice,splice在只有一個參數的時候表示保留的數組的長度
vm.items.splice(newLength)

異步更新隊列

  • Vue 在更新 DOM 時是異步執(zhí)行的
  • 只要偵聽到數據變化,Vue 將開啟一個隊列,并緩沖在同一事件循環(huán)中發(fā)生的所有數據變更。如果同一個 watcher 被多次觸發(fā),只會被推入到隊列中一次(會在緩沖時去除重復數據)
  • 所以如果想要在數據更新之后拿到數據,最好使用Vue.nextTick(callback)vm.$nextTick()實例方法
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容