Vue data的資料響應式到底是如何實現的
阿新 • • 發佈:2020-02-13
研究過程
一般形式
data:{ n:0 } :以這樣的方式儲存資料,vue能夠監聽其變化嗎?顯然是不能的。
使用Obj.defineProperty
let data1 = {} Object.defineProperty(data1,'n',{ value: 0 })
為什麼要使用defineProperty呢?這不是把一般形式複雜化了嗎?
引出主角getter setter。
如果我們想對資料監聽進行處理呢?(假設修改的資料必須>=0)
let data2 = {} data2._n = 0 Object.defineProperty(data2,{ get(){ return this._n },set(value){ if(value<0) return //在此處可以對資料的修改進行操作 this._n = value } })
使用代理
如果對方直接修改data2._n怎麼辦?我們讓data2變成匿名物件!
let data3 = proxy({ data:{n:0} }) //括號裡是匿名物件,無法訪問 function proxy({data}){ const obj = {} Object.defineProperty(obj,{ get(){ return data.n },set(value){ if(value<0)return data.n = value } }) return obj // obj 就是代理 }
代理是什麼?
- 對data的屬性的讀寫,全權交給另一個物件obj負責,那麼obj就是data的代理
- data.n不使用,偏要使用obj.n來操作data.n
如果使用者自己給匿名物件起了個名字怎麼辦呢?
MyData = { n:0 } let data3 = proxy({ data:MyData }) MyData.n = -1 //成功賦值為-1
這種情況,我們也要進行攔截處理。
//在4.中的proxy函式中加入這幾行 let value = data.n Object.defineProperty(data,{ get(){ return value },set(newValue){ if(newValue<0)return value = newValue } })
這樣,我們就對data進行了監聽。
data域的一個bug
new Vue({ data:{ obj:{ a:0 } },template:` <div @click="set">{{ obj.b }}</div> `,methods:{ set(){ this.obj.b = 1 } } }) //bug:vue無法監聽一開始data域中不存在的obj.b
解決方法:
data的初始化中加入b
data:{ obj:{ a:0,b:undefined //注意,vue中的null和undefined都不會被渲染出來 } }
使用Vue.set(this.obj,'b',1)
陣列的長度又不固定,怎麼提前宣告?
- 使用Vue.set (不推薦)
- 使用this.array.push (被Vue改寫過的push,實現了代理和監聽)
詳見vue文件,變異方法 章節
總結
//看看下面的程式碼,發現了什麼? let data = proxy({ data:myData5 }) let vm = new Vue({ data: myData })
Vue正是使用了這種代理和監聽的設計模式,形成的資料響應式。
流程:宣告資料 => 監聽資料 => 代理資料 => 返回資料
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。