本文能幫你做什么?好奇vue雙向綁定的同學,可以部分緩解好奇心,還可以幫你了解如何實現$watch。
前情回顧
我之前寫了一篇沒什么干貨的文章,并且刨了一個大坑。
今天,打算來填一天,并再刨一個。
不過話說說回來了,看本文之前,如果不知道Object.defineProperty,還必須看看解析神奇的Object.defineProperty
不得不感慨vue的作者,人長得帥,碼寫的也好,本文是根據作者源碼,摘取出來的
本文將實現什么
正如上一篇許下的承諾一樣,本文要實現一個$wacth
const v = new Vue({ data:{ a:1, b:2 }})v.$watch("a",()=>console.log("哈哈,$watch成功"))setTimeout(()=>{ v.a = 5},2000) //打印 哈哈,$watch成功為了幫助大家理清思路。。我們就做最簡單的實現。。只考慮對象不考慮數組
1. 實現 observer
思路:我們知道Object.defineProperty的特性了,我們就利用它的set和get。我們將要observe的對象,通過遞歸,將它所有的屬性,包括子屬性的屬性,都給加上set和get。這樣的話,給這個對象的某個屬性賦值,就會觸發set。開始吧
export default class Observer{ constructor(value) { this.value = value this.walk(value) } //遞歸。。讓每個字屬性可以observe walk(value){ Object.keys(value).forEach(key=>this.convert(key,value[key])) } convert(key, val){ defineReactive(this.value, key, val) }}export function defineReactive (obj, key, val) { var childOb = observe(val) Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: ()=>val, set:newVal=> { childOb = observe(newVal)//如果新賦值的值是個復雜類型。再遞歸它,加上set/get。。 } })}export function observe (value, vm) { if (!value || typeof value !== 'object') { return } return new Observer(value)}代碼很簡單,就給每個屬性(包括子屬性)都加上get/set,這樣的話,這個對象的,有任何賦值,就會觸發set方法。。
所以,我們是不是應該寫一個消息-訂閱器呢?
這樣的話,一觸發set方法,我們就發一個通知出來,然后,訂閱這個消息的,就會怎樣?對咯。、收到消息、觸發回調。
2. 消息-訂閱器
很簡單,我們維護一個數組,,這個數組,就放訂閱著,一旦觸發notify,訂閱者就調用自己的update方法
export default class Dep { constructor() { this.subs = [] } addSub(sub){ this.subs.push(sub) } notify(){ this.subs.forEach(sub=>sub.update()) }}所以,每次set函數,調用的時候,我們是不是應該,觸發notify,對吧。所以我們把代碼補充完整
export function defineReactive (obj, key, val) { var dep = new Dep() var childOb = observe(val) Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: ()=>val, set:newVal=> { var value = val if (newVal === value) { return } val = newVal childOb = observe(newVal) dep.notify() } }) }
新聞熱點
疑難解答
圖片精選