摘要:但中的視圖渲染是實(shí)時(shí)的,視圖層依賴于數(shù)據(jù)層,數(shù)據(jù)變化了,視圖層也會(huì)跟著變化,不需要手動(dòng)更新。被讀取被修改運(yùn)行所有運(yùn)行看看我們加多一個(gè)試試這就是中的一個(gè)依賴對(duì)應(yīng)多個(gè)
開(kāi)始
聲明一個(gè)對(duì)象man,可以視為vue中的data
let man = { height: 180, weight: 70, wealth: 100000000 }添加Observer
作用在于將參數(shù)對(duì)象的屬性變?yōu)轫憫?yīng)式,只要對(duì)象的屬性被讀取或者被修改都能觀察到。然后新建一個(gè)Observer實(shí)例,將man作為參數(shù)扔進(jìn)去。這里的proxyData是將man的屬性代理到以man為參數(shù)的Observer實(shí)例上去。
class Observer { constructor(obj) { this.walk(obj) } walk(obj) { Object.keys(obj).forEach(prop => { this[prop] = obj[prop] this.proxyData(obj, prop) this.defineReactive(this, prop, obj[prop]) }) } proxyData(obj, prop) { let _this = this Object.defineProperty(obj, prop, { get() { return _this[prop] }, set(newVal) { _this[prop] = newVal } }) } defineReactive(obj, prop, val) { Object.defineProperty(obj, prop, { get() { console.log(`${prop} - 被讀??!`) return val }, set(newVal) { if (newVal == val) return val = newVal console.log(`${prop} - 被修改!`) } }) } } new Observer(man)
這時(shí)打印一下man
現(xiàn)在man的屬性都是由Observer實(shí)例所對(duì)應(yīng)的屬性的getter來(lái)返回,只有在查看時(shí)會(huì)被觸發(fā)
對(duì)man的屬性進(jìn)行修改也會(huì)觸發(fā)實(shí)例對(duì)應(yīng)屬性的setter
現(xiàn)在的Watcher有點(diǎn)像vue中的computed,實(shí)際上就是定義一個(gè)計(jì)算屬性,這個(gè)計(jì)算屬性依賴于前面man中的某些屬性,由他們計(jì)算而得。
class Watcher { constructor(obj, prop, computed) { this.getVal(obj, prop, computed) } getVal(obj, prop, computed) { Object.defineProperty(obj, prop, { get() { console.log(`computed屬性 - ${prop}被讀取!`) return computed() }, set() { console.error("計(jì)算屬性不可被修改!") } }) } } new Watcher(man, "strength", () => { let {height, weight} = man if (height > 160 && weight > 70) return "strong" return "weak" })
看起來(lái)沒(méi)什么問(wèn)題,所依賴的屬性如果變了,計(jì)算屬性只要再被查看(get方法)一次就可以更新了。但vue中的視圖渲染是實(shí)時(shí)的,視圖層依賴于數(shù)據(jù)層,數(shù)據(jù)變化了,視圖層也會(huì)跟著變化,不需要手動(dòng)更新。類比到這個(gè)例子就是計(jì)算屬性如何才能在其所依賴的屬性發(fā)生變化時(shí)被通知從而觸發(fā)應(yīng)有的事件?
這時(shí)我們先給Watcher加多一個(gè)callback,用于處理當(dāng)依賴的數(shù)據(jù)被修改時(shí),我這個(gè)計(jì)算屬性該怎么響應(yīng)
比如當(dāng)依賴被修改時(shí),我們就把這個(gè)計(jì)算屬性的值打印出來(lái)
class Watcher { constructor(obj, prop, computed, callback) { this.getVal(obj, prop, computed, callback) } new Watcher(man, "strength", () => { let {height, weight} = man if (height > 160 && weight > 70) return "strong" return "weak" }, () => { console.log(`i am so ${man.strength} !`) })
一切都準(zhǔn)備好了,接下來(lái)就是該如何實(shí)現(xiàn)?
我們先看下Watcher中g(shù)etVal這個(gè)方法
getVal(obj, prop, computed, callback) { Object.defineProperty(obj, prop, { get() { console.log(`computed屬性 - ${prop}被讀取!`) return computed() }, set() { console.error("計(jì)算屬性不可被修改!") } }) }
當(dāng)我們查看計(jì)算屬性時(shí),會(huì)調(diào)用computed這個(gè)方法,相當(dāng)于查看了其所依賴的height和weight屬性,而在上面我們已經(jīng)讓man的所有屬性都擁有了get方法,即他們被查看時(shí)我們是不是可以把callback塞給他們?
這時(shí)候我們引進(jìn)一個(gè)橋梁,來(lái)連接Watcher和Observer。
Dep的用處在于當(dāng)某一個(gè)屬性(以下稱‘自己’)被依賴了,將依賴自己的粉絲(們)--也就是Watcher(s),收集起來(lái),假如自己發(fā)生了變化,能夠及時(shí)通知粉絲們。
class Dep { constructor() { this.deps = [] } getDeps() { if (!Dep.target || this.deps.includes(Dep.target)) return console.log("依賴添加", Dep.target) this.deps.push(Dep.target) } notify() { this.deps.forEach(dep => { dep() }) } }
這里的Dep.target就是前面所說(shuō)的callback方法了。這時(shí)我們改一下Watcher中的getVal
getVal(obj, prop, computed, callback) { Object.defineProperty(obj, prop, { get() { Dep.target = callback console.log(`computed屬性 - ${prop}被讀?。) return computed() }, set() { console.error("計(jì)算屬性不可被修改!") } }) }
在計(jì)算屬性被查看時(shí),將callback賦值給Dep.target,接下來(lái)就會(huì)調(diào)用其所依賴屬性的getter,我們只要在getter里把callback給收集起來(lái)就行了。接下來(lái)修改依賴屬性的getter方法。
defineReactive(obj, prop, val) { let dep = new Dep() Object.defineProperty(obj, prop, { get() { console.log(`${prop} - 被讀?。) dep.getDeps() // 依賴收集 return val }, set(newVal) { if (newVal == val) return val = newVal console.log(`${prop} - 被修改!`) } }) }
這時(shí)watcher的callback都被依賴屬性給收集起來(lái)了,當(dāng)依賴屬性發(fā)生變化時(shí)只要去運(yùn)行這些callback就可以了。接下來(lái)就是修改依賴屬性的setter方法。
defineReactive(obj, prop, val) { let dep = new Dep() Object.defineProperty(obj, prop, { get() { console.log(`${prop} - 被讀??!`) dep.getDeps() return val }, set(newVal) { if (newVal == val) return val = newVal console.log(`${prop} - 被修改!`) dep.notify() // 運(yùn)行所有callback } }) }
運(yùn)行看看
我們加多一個(gè)Watcher試試
new Watcher(man, "isGreat", () => { let {height, weight, wealth} = man if (height > 180 && weight > 70 && wealth > 100000) return "Great!" return "not good enough ..." }, () => { console.log(`they say i am ${man.isGreat}`) })
這就是vue中的一個(gè)依賴對(duì)應(yīng)多個(gè)Watcher
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/101580.html
摘要:總結(jié)最后我們依照下圖參考深入淺出,再來(lái)回顧下整個(gè)過(guò)程在后,會(huì)調(diào)用函數(shù)進(jìn)行初始化,也就是過(guò)程,在這個(gè)過(guò)程通過(guò)轉(zhuǎn)換成了的形式,來(lái)對(duì)數(shù)據(jù)追蹤變化,當(dāng)被設(shè)置的對(duì)象被讀取的時(shí)候會(huì)執(zhí)行函數(shù),而在當(dāng)被賦值的時(shí)候會(huì)執(zhí)行函數(shù)。 前言 Vue 最獨(dú)特的特性之一,是其非侵入性的響應(yīng)式系統(tǒng)。數(shù)據(jù)模型僅僅是普通的 JavaScript 對(duì)象。而當(dāng)你修改它們時(shí),視圖會(huì)進(jìn)行更新。這使得狀態(tài)管理非常簡(jiǎn)單直接,不過(guò)理解...
摘要:淺析響應(yīng)式原理一的特點(diǎn)之一是響應(yīng)式,視圖隨著數(shù)據(jù)的更新而更新,在視圖中修改數(shù)據(jù)后實(shí)例中的數(shù)據(jù)也會(huì)同步更新。對(duì)于每個(gè)響應(yīng)式數(shù)據(jù),會(huì)有兩個(gè)實(shí)例,第一個(gè)是在中的閉包遍歷,用途顯而易見(jiàn)。接收一個(gè)回調(diào)函數(shù),會(huì)在重新求值且值更新后執(zhí)行。 淺析Vue響應(yīng)式原理(一) Vue的特點(diǎn)之一是響應(yīng)式,視圖隨著數(shù)據(jù)的更新而更新,在視圖中修改數(shù)據(jù)后Vue實(shí)例中的數(shù)據(jù)也會(huì)同步更新。內(nèi)部借助依賴(下文中的Dep類)...
摘要:響應(yīng)式數(shù)據(jù)響應(yīng)式數(shù)據(jù)不是憑空出現(xiàn)的。對(duì)于對(duì)象而言,如果是之前不存在的屬性,首先可以將進(jìn)行響應(yīng)化處理比如調(diào)用,然后將對(duì)具體屬性定義監(jiān)聽(tīng)比如調(diào)用函數(shù),最后再去做賦值,可能具體的處理過(guò)程千差萬(wàn)別,但是內(nèi)部實(shí)現(xiàn)的原理應(yīng)該就是如此僅僅是猜測(cè)。 前言 首先歡迎大家關(guān)注我的Github博客,也算是對(duì)我的一點(diǎn)鼓勵(lì),畢竟寫東西沒(méi)法獲得變現(xiàn),能堅(jiān)持下去也是靠的是自己的熱情和大家的鼓勵(lì)。 國(guó)內(nèi)前端算...
摘要:所以我今后打算把每一個(gè)內(nèi)容分成白話版和源碼版。有什么錯(cuò)誤的地方,感謝大家能夠指出響應(yīng)式系統(tǒng)我們都知道,只要在實(shí)例中聲明過(guò)的數(shù)據(jù),那么這個(gè)數(shù)據(jù)就是響應(yīng)式的。什么是響應(yīng)式,也即是說(shuō),數(shù)據(jù)發(fā)生改變的時(shí)候,視圖會(huì)重新渲染,匹配更新為最新的值。 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 V...
摘要:需要指令解析器,對(duì)每個(gè)元素節(jié)點(diǎn)的指令進(jìn)行掃描和解析,根據(jù)指令模板替換數(shù)據(jù),以及綁定相應(yīng)的更新函數(shù)。然后將模版中的變量替換成數(shù)據(jù),渲染,將每個(gè)指令對(duì)應(yīng)的節(jié)點(diǎn)綁定更新函數(shù),添加監(jiān)聽(tīng)數(shù)據(jù)的訂閱者,一旦數(shù)據(jù)發(fā)生變動(dòng),收到通知,更新視圖。 用了Vue也有兩年時(shí)間了,一直以來(lái)都是只知其然,不知其所以然,為了能更好的使用Vue不被Vue所奴役,學(xué)習(xí)一下Vue底層的基本原理。 Vue官網(wǎng)有一段這樣的介...
閱讀 1538·2023-04-26 02:03
閱讀 4729·2021-11-22 13:53
閱讀 4633·2021-09-09 11:40
閱讀 3801·2021-09-09 09:34
閱讀 2136·2019-08-30 13:18
閱讀 3511·2019-08-30 11:25
閱讀 3305·2019-08-26 14:06
閱讀 2554·2019-08-26 13:52