和尤雨溪一塊兒進階vue

上圖,無圖無真相vue

bf36103996e041cca3bda6ea2679d990


花了400大洋買了frontedmasters的一個月的會員,就是爲了看男神的這份vue教程,沒有中文字幕,痛苦地堅持啃完了,建議有錢而且英語好的人直接買會員去官網看視頻,尤大神人長得帥,業務水平高,英語還超蘇,對不起,忍不住犯了會兒花癡,若是沒錢英語又渣的人只能看個人總結了,看個人文章的好處就是不用花錢,不用被英語折磨,壞處就是本人的文字水平和業務水平真的有限,不會一步步引導式地分析原理和代碼的實現,只能貼代碼和盡我所能來解釋了,能理解多少就看你們的水平了,這算不算無良商家,不包售後啊,哈哈。react

這個系列文章將從下面幾個方面來介紹vue數組

  1. reactivity(響應式)閉包

  2. plugin(插件)app

  3. render(渲染函數)框架

  4. routing(路由)ide

  5. state-management(狀態管理)函數

  6. international(多語言支持)this

1 reactivityspa

相信瞭解過vue的同窗都知道,vue是MVVM框架,最大的特色就是雙向數據綁定,數據Model修改了以後視圖View會自動更新, view也能夠經過v-model的將ViewModel的變化同步到Model裏面

這篇文章要探討的問題:vue是如何監控數據的變化從而自動更新視圖,也就是vue響應式是如何實現的,咱們一步步來看。

1.1. getter and setter

考慮下面這段代碼,一個簡單的代數計算關係,b依賴a, b是a的10倍

 var a= 10; var b = a*10; a = 20
 //b = ? 如何監聽b的變化
複製代碼

請認真思考一下再往下看:當每次改變a的值的時候,如何監聽a的變化而且更新b,保證他們的數學關係b是a的10倍?

給你們留了10行空白,不知道你們有沒有認真思考上面的問題?

不賣關子了,直接用兩個數值,咱們目前沒法監控,能夠換種思路,直接監控一個數值變量行不通,咱們能夠監控一個對象屬性的變化,在屬性改變的時候收集它的依賴,就能夠觸發依賴的更新

js有一個方法Object.defineProperty能夠劫持屬性的讀取器getter和setter, 來看個例子

 let obj = {
 a:10
 };
 observer(obj, 'a');
 obj.a = 20; let b = obj.a;
 obj.a = 30; // 實現一個函數,能夠監控到對象屬性的變化
 function observer(obj, key) { Object.defineProperty(obj, key, {
 configurable: true, // 能夠被delete
 enumerable: true, // for in迭代
 set(val) { console.log(`對象的屬性${key}被賦值了${val}`);
 }, get() { console.log(`對象的屬性${key}被讀取了`);
 }
 });
 } //對象的屬性a被賦值了20
 //對象的屬性a被讀取了
 //對象的屬性a被賦值了30複製代碼

從上面的例子能夠看出, 咱們只要用 Object.defineProperty重寫對象的屬性讀寫器getter和setter就能夠監聽到對象屬性的變化,上面的代碼只能夠監控一個屬性的變化,對於對象的全部屬性,須要遍歷轉換,改造一下observer方法(這裏只考慮一層對象,深層次的須要遞歸遍歷,數組的監控也須要另寫方法,有興趣的去看vue的源碼)

 function observer(obj) { Object.keys(obj).forEach(key => { let internalValue = obj[key] Object.defineProperty(obj, key, { get() { console.log(`getting key "${key}": ${internalValue}`) return internalValue
 }, set(newVal) { console.log(`setting key "${key}" to: ${internalValue}`)
 internalValue = newVal
 }
 })
 })
 }
複製代碼

如今咱們已經能夠監聽到一個對象全部屬性的變化了,最開始提出的問題已經解決了一半了,接下來要解決的問題是當屬性變化的時候,如何收集它的依賴,觸發依賴的更新呢?也就是咱們這篇文章的主題,如何實現一個簡易的響應式系統。

思路就是:在讀取屬性的時候收集依賴,在改變屬性值的時候觸發依賴的更新

  1. 實現一個observer,劫持對象屬性的getter和setter

  2. 實現一個全局的訂閱器Dep,能夠追加訂閱者,和通知依賴更新

  3. 在讀取屬性的時候追加當前依賴到Dep中,在設置屬性的時候循環觸發依賴的更新

按照這個思路,實習一個簡易的響應式系統。

 // 全局的依賴收集器Dep
 window.Dep = class Dep { constructor() { this.subscribers = new Set(); // 保證依賴不重複添加
 } // 追加訂閱者
 depend() { if(activeUpdate) { // activeUpdate註冊爲訂閱者
 this.subscribers.add(activeUpdate)
 }
 } // 運行全部的訂閱者更新方法
 notify() { this.subscribers.forEach(sub => {
 sub();
 })
 }
 } let activeUpdate // js單線程語言,任一時刻只能有一個函數執行,也就是任一時刻,只可能有一個依賴在更新 //用一個全局變量activeUpdate來標誌,這裏有點很差理解,你們多想一想就會明白autorun的巧妙之處了
 // autorun接受一個更新函數
 function autorun(update) { function wrapperUpdate() {
 activeUpdate = wrapperUpdate
 update() // wrapperUpdate, 閉包
 activeUpdate = null;
 }
 wrapperUpdate();
 } function observer(obj) { Object.keys(obj).forEach(key => { var dep = new Dep(); // 爲每一個key建立訂閱器Dep
 let internalValue = obj[key] Object.defineProperty(obj, key, {
 get() { // console.log(`getting key "${key}": ${internalValue}`)
 // 將當前正在運行的更新函數追加進訂閱者列表
 if(activeUpdate) { 
 dep.depend() //收集依賴
 } return internalValue
 },
 set(newVal) { 	//console.log(`setting key "${key}" to: ${internalValue}`)
 	// 加個if判斷,數據發生變化再觸發更新
 	if(internalValue !== newVal) {
 	 internalValue = newVal
 dep.notify() // 觸發依賴的更新
 	}
 }
 })
 })
 } let state = { count:0
 }
 observer(state);
 autorun(() => { console.log('state.count發生變化了', state.count)
 })
 state.count = state.count + 5; // state.count發生變化了 0
 // state.count發生變化了 5複製代碼

這篇文章先更到這裏,後續內容有時間繼續更新,雖然更新時間不定,可是計劃月底更新完,但願喜歡的小夥伴多多關注和支持,謝謝。

相關文章
相關標籤/搜索