摘要:解決第一個問題很簡單,我們把某個屬性的值對應值變化時需要執行的函數抽象成一個對象,然后把這個對象當成是依賴,推入依賴管理中。的實現有了以上的考慮,那個依賴對象在中就是。新值作為添加的第一個函數,很自豪。
看這篇之前,如果沒有看過之前的文章,可拉到文章末尾查看之前的文章。
前言在 step2 中,我們實現了一個管理依賴的 Dep ,但是僅僅使用這個類并不能完成我們想實現的功能,而且代碼的解耦上也有點小問題。以下是在 step2 中最后說的幾個問題:
解耦不完全,需要傳遞參數
沒有地方可以移除依賴
考慮問題第一個問題顯示出來一個問題,由于我們的依賴是函數,為了函數的執行我們只能講參數傳進去,這個問題的根源在于我們的依賴是一個函數;
第二個問題其實反映出當前的 dep 實例只有在 defineReactive 中使用,而沒有暴露出來,只要在外部有這個實例的引用,那么我們就能順利的調用移除依賴了(removeSub)。
解決第一個問題很簡單,我們把某個屬性的值、對應值變化時需要執行的函數抽象成一個對象,然后把這個對象當成是依賴,推入依賴管理中。
在第一個問題的基礎上第二個問題就能解決了,我們只需要把 dep 的引用保存在依賴對象中就可以了。
當然我也是在看了 Vue 源碼的基礎上才有了上面的解決辦法,這里不得不給尤大大贊一個。
Watcher 的實現有了以上的考慮,那個依賴對象在 Vue 中就是 Watcher。
let Watcher = function(object, key, callback){ this.obj = object this.getter = key this.cb = callback this.dep = null this.value = undefined this.get = function(){ Dep.target = this let value = this.obj[this.getter] Dep.target = null return value } this.update = function(){ const value = this.obj[this.getter] const oldValue = this.value this.value = value this.cb.call(this.obj, value, oldValue) } this.addDep = function(dep) { this.dep = dep } this.value = this.get() }
上述代碼實現了一個 Watcher ,為了方便起見我這里叫它監聽。
該類的實例保存了需要監聽的對象(object),取值方法(key),對應的回調(callback),需要監聽的值(value),以及取值函數(get)和觸發函數(update),這樣我們就把依賴相關的所有內容保存在這個 Watcher 的實例中。
為了保存對 Dep 的引用,在 Watcher 中設置了 dep ,用于存放該監聽被那個 Dep 給引用了。
由于在 Watcher 實例化的時候,我們已經對相應的值取了一次值,就是將以下代碼放在在 Watcher 中
Dep.target = function(newValue, oldValue){ console.log("我被添加進去了,新的值是:" + newValue) } object.test Dep.target = null
對應的代碼為
this.get = function(){ Dep.target = this let vaule = this.obj[this.getter] Dep.target = null return value } this.value = this.get()
所以在編寫代碼的時候,不用特地的去觸發 get 添加依賴。
那么針對 Watcher 我們需要改造一下之前實現的 Dep 和 defineReactive 函數。
由于依賴變成了 Watcher 所以在 Dep 中 notify 應該改成 Watcher 下的觸發函數:update
由于 watcher 中存放了變量的狀態,所以不需要在 defineReactive 函數中傳入參數
let Dep = function(){ this.subs = [] this.addSub = function(sub){ this.subs.push(sub) } this.removeSub = function(sub){ const index = this.subs.indexOf(sub) if (index > -1) { this.subs.splice(index, 1) } } this.notify = function(){ // 修改觸發方法 this.subs.forEach(watcher=>watcher.update()) } } Dep.target = null let defineReactive = function(object, key, value){ let dep = new Dep() Object.defineProperty(object, key, { configurable: true, enumerable: true, get: function(){ if(Dep.target){ dep.addSub(Dep.target) // 添加 watcher 對 dep 的引用 Dep.target.addDep(dep) } return value }, set: function(newValue){ if(newValue != value){ value = newValue // 不需要特地傳入參數 dep.notify() } } }) }
接下來我們來測試一下
let object = {} defineReactive(object, "test", "test") let watcher = new Watcher(object, "test", function(newValue, oldValue){ console.log("作為 watcher 添加的第一個函數,很自豪。新值:" + newValue) }) object.test = "test2" // 作為 watcher 添加的第一個函數,很自豪。新值:test2 let watcher2 = new Watcher(object, "test", function(newValue, oldValue){ console.log("作為 watcher 添加的第二個函數,也很自豪。新值:" + newValue) }) object.test = "test3" // 作為 watcher 添加的第一個函數,很自豪。新值:test3 // 作為 watcher 添加的第二個函數,也很自豪。新值:test3 // 接著我們來試一下刪除依賴,把 watcher2 給刪除 watcher2.dep.removeSub(watcher2) object.test = "test4" // 作為 watcher 添加的第一個函數,很自豪。新值:test4
通過上面代碼,我們成功解耦,用一個監聽來處理某個屬性的內容(oldValue, newValue, callback),而且我們也能夠去除 dep 中沒用的依賴。
當然這個 Watcher 還是需要優化的,比如被多個 Dep 引用,這個就得存一個數組,之后繼續優化。
點擊查看相關代碼
系列文章地址VUE - MVVM - part1 - defineProperty
VUE - MVVM - part2 - Dep
VUE - MVVM - part3 - Watcher
VUE - MVVM - part4 - 優化Watcher
VUE - MVVM - part5 - Observe
VUE - MVVM - part6 - Array
VUE - MVVM - part7 - Event
VUE - MVVM - part8 - 優化Event
VUE - MVVM - part9 - Vue
VUE - MVVM - part10 - Computed
VUE - MVVM - part11 - Extend
VUE - MVVM - part12 - props
VUE - MVVM - part13 - inject & 總結
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/94182.html
摘要:關于中的的實現,差不多也就這樣了,當然這僅僅是基礎的實現,而且視圖層層渲染抽象成一個函數。不同于中的實現,這里少了很多各種標記和應用標記的過程。 看這篇之前,如果沒有看過之前的文章,可拉到文章末尾查看之前的文章。 回顧 首先我們思考一下截止當前,我們都做了什么 通過 defineReactive 這個函數,實現了對于數據取值和設置的監聽 通過 Dep 類,實現了依賴的管理 通過 Wa...
摘要:了解之后我們來實現它,同樣的為了方便理解我寫成了一個類這里的一般是的實例將屬性代理到實例下的構造函數我們實現了代理屬性和更新計算屬性的值,同時依賴沒變化時,也是不會觸發的更新,解決了以上的個問題。 看這篇之前,如果沒有看過之前的文章,移步拉到文章末尾查看之前的文章。 回顧 先捋一下,之前我們實現的 Vue 類,主要有一下的功能: 屬性和方法的代理 proxy 監聽屬性 watche...
摘要:調用父類的方法類在我們上一步已經實現。我們先實現的綁定,因為是要被監聽,所以要進行進一步的處理。調用父類的方法方法綁定完事,其實就這么簡單。 看這篇之前,如果沒有看過之前的文章,可拉到文章末尾查看之前的文章。 前言 激動人心的時候即將來臨,之前我們做的 8 步,其實都在為這一步打基礎,這一步,我們來簡單實現一個 Vue 對象,還沒有看過之前代碼的同學,請確認看過之前的文章。 主要實現內...
摘要:具體代碼執行方式進入到的目錄下,命令行運行即可。確保為一個對象如果對象下有則不需要再次生成函數返回該對象的實例,這里判斷了如果該對象下已經有實例,則直接返回,不再去生產實例。這就確保了一個對象下的實例僅被實例化一次。 看這篇之前,如果沒有看過之前的文章,可拉到文章末尾查看之前的文章。 回顧 在 step4 中,我們大致實現了一個 MVVM 的框架,由3個部分組成: defineRe...
摘要:看這篇之前,如果沒看過先移步看實現中。同樣的,在取值時收集依賴,在設置值當值發生變化時觸發依賴。中實現了一個的類來處理以上兩個問題,之后再說。以下語法下的,源碼中差不多就這樣點擊查看相關代碼系列文章地址優化優化總結 看這篇之前,如果沒看過 step1 先移步看 實現 VUE 中 MVVM - step1 - defineProperty。 在上一篇我們大概實現了,Vue 中的依賴收集和...
閱讀 2823·2021-10-26 09:48
閱讀 1693·2021-09-22 15:22
閱讀 4076·2021-09-22 15:05
閱讀 632·2021-09-06 15:02
閱讀 2619·2019-08-30 15:52
閱讀 2122·2019-08-29 18:38
閱讀 2771·2019-08-28 18:05
閱讀 2340·2019-08-26 13:55