精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

探索Vue.js響應式原理

開發(fā) 前端
接下來我根據(jù)個人理解,和大家一起探索下 Vue.js 中的響應式原理,一起來看看吧。

 提到“響應式”三個字,大家立刻想到啥?響應式布局?響應式編程?

從字面意思可以看出,具有“響應式”特征的事物會根據(jù)條件變化,使得目標自動作出對應變化。比如在“響應式布局”中,頁面根據(jù)不同設(shè)備尺寸自動顯示不同樣式。

Vue.js 中的響應式也是一樣,當數(shù)據(jù)發(fā)生變化后,使用到該數(shù)據(jù)的視圖也會相應進行自動更新。

接下來我根據(jù)個人理解,和大家一起探索下 Vue.js 中的響應式原理,如有錯誤,歡迎指點😺~~

一、Vue.js 響應式的使用

現(xiàn)在有個很簡單的需求,點擊頁面中 “leo” 文本后,文本內(nèi)容修改為“你好,前端自習課”。

我們可以直接操作 DOM,來完成這個需求:

  1. <span id="name">leo</span>  
  1. const node = document.querySelector('#name')  
  2. node.innerText = '你好,前端自習課'

實現(xiàn)起來比較簡單,當我們需要修改的數(shù)據(jù)有很多時(比如相同數(shù)據(jù)被多處引用),這樣的操作將變得復雜。

既然說到 Vue.js,我們就來看看 Vue.js 怎么實現(xiàn)上面需求: 

  1. <template>  
  2.   <div id="app">  
  3.     <span @click="setName">{{ name }}</span>  
  4.   </div>  
  5. </template>  
  6. <script>  
  7. export default {  
  8.   name: "App",  
  9.   data() {  
  10.     return {  
  11.       name: "leo",  
  12.     };  
  13.   },  
  14.   methods: {  
  15.     setName() {  
  16.       this.name = "你好,前端自習課" 
  17.     },  
  18.   },  
  19. };  
  20. </script> 

觀察上面代碼,我們通過改變數(shù)據(jù),來自動更新視圖。當我們有多個地方引用這個 name 時,視圖都會自動更新。 

  1. <template>  
  2.   <div id="app">  
  3.     <span @click="setName">{{ name }}</span>  
  4.     <span>{{ name }}</span>  
  5.     <span>{{ name }}</span>  
  6.     <span>{{ name }}</span>  
  7.   </div>  
  8. </template> 

當我們使用目前主流的前端框架 Vue.js 和 React 開發(fā)業(yè)務(wù)時,只需關(guān)注頁面數(shù)據(jù)如何變化,因為數(shù)據(jù)變化后,視圖也會自動更新,這讓我們從繁雜的 DOM 操作中解脫出來,提高開發(fā)效率。

二、回顧觀察者模式

前面反復提到“通過改變數(shù)據(jù),來自動更新視圖”,換個說法就是“數(shù)據(jù)改變后,使用該數(shù)據(jù)的地方被動發(fā)生響應,更新視圖”。

是不是有種熟悉的感覺?數(shù)據(jù)無需關(guān)注自身被多少對象引用,只需在數(shù)據(jù)變化時,通知到引用的對象即可,引用的對象作出響應。恩,有種觀察者模式的味道?

關(guān)于觀察者模式,可閱讀我之前寫的《圖解設(shè)計模式之觀察者模式(TypeScript)》

1. 觀察者模式流程

觀察者模式表示一種“一對多”的關(guān)系,n 個觀察者關(guān)注 1 個被觀察者,被觀察者可以主動通知所有觀察者。接下圖:

在這張圖中,粉絲想及時收到“前端自習課”最新文章,只需關(guān)注即可,“前端自習課”有新文章,會主動推送給每個粉絲。該過程中,“前端自習課”是被觀察者,每位“粉絲”是觀察者。

2. 觀察者模式核心

觀察者模式核心組成包括:n 個觀察者和 1 個被觀察者。這里實現(xiàn)一個簡單觀察者模式:

2.1 定義接口 

  1. // 觀察目標接口  
  2. interface ISubject {  
  3.     addObserver: (observer: Observer) => void; // 添加觀察者  
  4.     removeObserver: (observer: Observer) => void; // 移除觀察者  
  5.     notify: () => void; // 通知觀察者  
  6.  
  7. // 觀察者接口  
  8. interface IObserver {  
  9.     update: () => void;  

2.2 實現(xiàn)被觀察者類 

  1. // 實現(xiàn)被觀察者類  
  2. class Subject implements ISubject {  
  3.     private observers: IObserver[] = [];  
  4.     public addObserver(observer: IObserver): void {  
  5.         this.observers.push(observer);  
  6.     }  
  7.     public removeObserver(observer: IObserver): void {  
  8.         const idx: number = this.observers.indexOf(observer);  
  9.         ~idx && this.observers.splice(idx, 1);  
  10.     }  
  11.     public notify(): void { 
  12.          this.observers.forEach(observer => {  
  13.             observer.update();  
  14.         });  
  15.     }  

2.3 實現(xiàn)觀察者類 

  1. // 實現(xiàn)觀察者類  
  2. class Observer implements IObserver {  
  3.     constructor(private name: string) { }  
  4.     update(): void {  
  5.         console.log(`${this.name} has been notified.`);  
  6.     }  

2.4 測試代碼 

  1. function useObserver(){  
  2.     const subject: ISubject = new Subject();  
  3.     const Leo = new Observer("Leo");  
  4.     const Robin = new Observer("Robin");  
  5.     const Pual = new Observer("Pual");  
  6.     subject.addObserver(Leo);  
  7.     subject.addObserver(Robin);  
  8.     subject.addObserver(Pual);  
  9.     subject.notify();  
  10.     subject.removeObserver(Pual);  
  11.     subject.notify();  
  12.  
  13. useObserver();  
  14. // [LOG]: "Leo has been notified."   
  15. // [LOG]: "Robin has been notified."   
  16. // [LOG]: "Pual has been notified."   
  17. // [LOG]: "Leo has been notified."   
  18. // [LOG]: "Robin has been notified."  

三、回顧 Object.defineProperty()

Vue.js 的數(shù)據(jù)響應式原理是基于 JS 標準內(nèi)置對象方法 Object.defineProperty() 方法來實現(xiàn),該方法不兼容 IE8 和 FF22 及以下版本瀏覽器,這也是為什么 Vue.js 只能在這些版本之上的瀏覽器中才能運行的原因。

理解 Object.defineProperty() 對我們理解 Vue.js 響應式原理非常重要。

Vue.js 3 使用 proxy 方法實現(xiàn)響應式,兩者類似,我們只需搞懂Object.defineProperty() , proxy 也就差不多理解了。

1. 概念介紹

Object.defineProperty() 方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現(xiàn)有屬性,并返回此對象。

語法如下: 

  1. Object.defineProperty(obj, prop, descriptor) 
  •  入?yún)⒄f明:

obj :要定義屬性的源對象;

prop :要定義或修改的屬性名稱或 Symbol;

descriptor :要定義或修改的屬性描述符,包括 configurable、enumerable、value、writable、get、set,具體的可以去參閱文檔

  •  出參說明:

修改后的源對象。

舉個簡單🌰例子: 

  1. const leo = {};  
  2. Object.defineProperty(leo, 'age', {  
  3.     value: 18,  
  4.     writable: true  
  5. })  
  6. console.log(leo.age); // 18  
  7. leo.age = 22 
  8. console.log(leo.age); // 22 

2. 實現(xiàn) getter/setter

我們知道 Object.defineProperty() 方法第三個參數(shù)是屬性描述符(descriptor),支持設(shè)置 get 和 set 描述符:

  •  get 描述符:當訪問該屬性時,會調(diào)用此函數(shù),默認值為 undefined ;
  •  set 描述符:當修改該屬性時,會調(diào)用此函數(shù),默認值為 undefined 。

一旦對象擁有了 getter/setter 方法,我們可以簡單將該對象稱為響應式對象。

這兩個操作符為我們提供攔截數(shù)據(jù)進行操作的可能性,修改前面示例,添加 getter/setter 方法: 

  1. let leo = {}, age = 18 
  2. Object.defineProperty(leo, 'age', {   
  3.     get(){  
  4.         // to do something  
  5.           console.log('監(jiān)聽到請求數(shù)據(jù)');  
  6.         return age;  
  7.     },  
  8.     set(newAge){  
  9.         // to do something  
  10.           console.log('監(jiān)聽到修改數(shù)據(jù)');  
  11.         age = newAge > age ? age : newAge  
  12.     }  
  13. })  
  14. leo.age = 20;  // 監(jiān)聽到修改數(shù)據(jù)  
  15. console.log(leo.age); // 監(jiān)聽到請求數(shù)據(jù)  // 18  
  16. leo.age = 10;  // 監(jiān)聽到修改數(shù)據(jù)  
  17. console.log(leo.age); // 監(jiān)聽到請求數(shù)據(jù)  // 10 

訪問 leo 對象的 age 屬性,會通過 get 描述符處理,而修改 age 屬性,則會通過 set 描述符處理。

四、實現(xiàn)簡單的數(shù)據(jù)響應式

通過前面兩個小節(jié),我們復習了“觀察者模式”和“Object.defineProperty()” 方法,這兩個知識點在 Vue.js 響應式原理中非常重要。

接下來我們來實現(xiàn)一個很簡單的數(shù)據(jù)響應式變化,需求如下:點擊“更新數(shù)據(jù)”按鈕,文本更新。

接下來我們將實現(xiàn)三個類:

  •  Dep 被觀察者類,用來生成被觀察者;
  •  Watcher 觀察者類,用來生成觀察者;
  •  Observer 類,將普通數(shù)據(jù)轉(zhuǎn)換為響應式數(shù)據(jù),從而實現(xiàn)響應式對象。

用一張圖來描述三者之間關(guān)系,現(xiàn)在看不懂沒關(guān)系,這小節(jié)看完可以再回顧這張圖:

1. 實現(xiàn)精簡觀察者模式

這里參照前面復習“觀察者模式”的示例,做下精簡: 

  1. // 實現(xiàn)被觀察者類  
  2. class Dep {  
  3.     constructor() {  
  4.         this.subs = [];  
  5.     }  
  6.     addSub(watcher) {  
  7.         this.subs.push(watcher);  
  8.     }  
  9.     notify(data) {  
  10.         this.subs.forEach(sub => sub.update(data));  
  11.     }  
  12.  
  13. // 實現(xiàn)觀察者類  
  14. class Watcher {  
  15.     constructor(cb) {  
  16.         this.cb = cb;  
  17.     }  
  18.     update(data) {  
  19.         this.cb(data);  
  20.     }  

Vue.js 響應式原理中,觀察者模式起到非常重要的作用。其中:

  •  Dep 被觀察者類,提供用來收集觀察者( addSub )方法和通知觀察者( notify )方法;
  •  Watcher 觀察者類,實例化時支持傳入回調(diào)( cb )方法,并提供更新( update )方法;

2. 實現(xiàn)生成響應式的類

這一步需要實現(xiàn) Observer 類,核心是通過 Object.defineProperty() 方法為對象的每個屬性設(shè)置 getter/setter,目的是將普通數(shù)據(jù)轉(zhuǎn)換為響應式數(shù)據(jù),從而實現(xiàn)響應式對象。

這里以最簡單的單層對象為例(下一節(jié)會介紹深層對象),如: 

  1. let initData = {  
  2.     text: '你好,前端自習課',  
  3.     desc: '每日清晨,享受一篇前端優(yōu)秀文章。'  
  4. }; 

接下來實現(xiàn) Observer 類: 

  1. // 實現(xiàn)響應式類(最簡單單層的對象,暫不考慮深層對象)  
  2. class Observer {  
  3.     constructor (node, data) {  
  4.         this.defineReactive(node, data)  
  5.     }  
  6.     // 實現(xiàn)數(shù)據(jù)劫持(核心方法)  
  7.     // 遍歷 data 中所有的數(shù)據(jù),都添加上 getter 和 setter 方法  
  8.     defineReactive(vm, obj) {  
  9.         //每一個屬性都重新定義get、set  
  10.         for(let key in obj){  
  11.             let value = obj[key], dep = new Dep();  
  12.             Object.defineProperty(obj, key, {  
  13.                 enumerable: true,  
  14.                 configurable: true,  
  15.                 get() {  
  16.                     // 創(chuàng)建觀察者  
  17.                     let watcher = new Watcher(v => vvm.innerText = v);  
  18.                     dep.addSub(watcher);  
  19.                     return value;  
  20.                 },  
  21.                 set(newValue) {  
  22.                     value = newValue 
  23.                     // 通知所有觀察者  
  24.                     dep.notify(newValue);  
  25.                 }  
  26.             })  
  27.         }  
  28.     }  

上面代碼的核心是 defineReactive 方法,它遍歷原始對象中每個屬性,為每個屬性實例化一個被觀察者(Dep),然后分別調(diào)用 Object.defineProperty() 方法,為每個屬性添加 getter/setter。

  •  訪問數(shù)據(jù)時,getter 執(zhí)行依賴收集(即添加觀察者),通過實例化 Watcher 創(chuàng)建一個觀察者,并執(zhí)行被觀察者的 addSub() 方法添加一個觀察者;
  •  修改數(shù)據(jù)時,setter 執(zhí)行派發(fā)更新(即通知觀察者),通過調(diào)用被觀察者的 notify() 方法通知所有觀察者,執(zhí)行觀察者 update() 方法。

3. 測試代碼

為了方便觀察數(shù)據(jù)變化,我們?yōu)?ldquo;更新數(shù)據(jù)”按鈕綁定點擊事件來修改數(shù)據(jù): 

  1. <div id="app"></div>  
  2. <button id="update">更新數(shù)據(jù)</button> 

測試代碼如下: 

  1. // 初始化測試數(shù)據(jù)  
  2. let initData = {  
  3.     text: '你好,前端自習課', 
  4.     desc: '每日清晨,享受一篇前端優(yōu)秀文章。'  
  5. };  
  6. const app = document.querySelector('#app'); 
  7.  // 步驟1:為測試數(shù)據(jù)轉(zhuǎn)換為響應式對象  
  8. new Observer(app, initData);  
  9. // 步驟2:初始化頁面文本內(nèi)容  
  10. app.innerText = initData.text;  
  11. // 步驟3:綁定按鈕事件,點擊觸發(fā)測試  
  12. document.querySelector('#update').addEventListener('click', function(){  
  13.     initData.text = `我們必須經(jīng)常保持舊的記憶和新的希望。`;  
  14.     console.log(`當前時間:${new Date().toLocaleString()}`)  
  15. }) 

測試代碼中,核心在于通過實例化 Observer,將測試數(shù)據(jù)轉(zhuǎn)換為響應式數(shù)據(jù),然后模擬數(shù)據(jù)變化,來觀察視圖變化。

每次點擊“更新數(shù)據(jù)”按鈕,在控制臺中都能看到“數(shù)據(jù)發(fā)生變化!”的提示,說明我們已經(jīng)能通過 setter 觀察到數(shù)據(jù)的變化情況。

當然,你還可以在控制臺手動修改 initData 對象中的 text 屬性,來體驗響應式變化~~

到這里,我們實現(xiàn)了非常簡單的數(shù)據(jù)響應式變化,當然 Vue.js 肯定沒有這么簡單,這個先理解,下一節(jié)看 Vue.js 響應式原理,思路就會清晰很多。

這部分代碼,我已經(jīng)放到我的 Github,地址:https://github.com/pingan8787/Leo-JavaScript/blob/master/Cute-Gist/Vue/Basics-Reactive-Demo.js

可以再回顧下這張圖,對整個過程會更清晰:

observer-watcher-dep.png

五、Vue.js 響應式實現(xiàn)

本節(jié)代碼:https://github.com/pingan8787/Leo-JavaScript/blob/master/Cute-Gist/Vue/leo-vue-reactive/

這里大家可以再回顧下下面這張官網(wǎng)經(jīng)典的圖,思考下前面講的示例。

(圖片來自:https://cn.vuejs.org/v2/guide/reactivity.html

上一節(jié)實現(xiàn)了簡單的數(shù)據(jù)響應式,接下來繼續(xù)通過完善該示例,實現(xiàn)一個簡單的 Vue.js 響應式,測試代碼如下: 

  1. // index.js  
  2. const vm = new Vue({  
  3.     el: '#app',  
  4.     data(){  
  5.         return {  
  6.             text: '你好,前端自習課',  
  7.             desc: '每日清晨,享受一篇前端優(yōu)秀文章。' 
  8.         }  
  9.     }  
  10. }); 

是不是很有內(nèi)味了,下面是我們最終實現(xiàn)后項目目錄: 

  1. - mini-reactive  
  2.     / index.html   // 入口 HTML 文件  
  3.   / index.js     // 入口 JS 文件  
  4.   / observer.js  // 實現(xiàn)響應式,將數(shù)據(jù)轉(zhuǎn)換為響應式對象  
  5.   / watcher.js   // 實現(xiàn)觀察者和被觀察者(依賴收集者)  
  6.   / vue.js       // 實現(xiàn) Vue 類作為主入口類  
  7.   / compile.js   // 實現(xiàn)編譯模版功能 

知道每一個文件功能以后,接下來將每一步串聯(lián)起來。

1. 實現(xiàn)入口文件

我們首先實現(xiàn)入口文件,包括 index.html / index.js  2 個簡單文件,用來方便接下來的測試。

1.1 index.html 

  1. <!DOCTYPE html>  
  2. <html lang="en">  
  3. <head>  
  4.     <script src="./vue.js"></script>  
  5.     <script src="./observer.js"></script>  
  6.     <script src="./compile.js"></script>  
  7.     <script src="./watcher.js"></script>  
  8. </head>  
  9. <body>  
  10.     <div id="app">{{text}}</div>  
  11.     <button id="update">更新數(shù)據(jù)</button>  
  12.     <script src="./index.js"></script>  
  13. </body>  
  14. </html> 

1.2 index.js 

  1. "use strict";  
  2. const vm = new Vue({  
  3.     el: '#app',  
  4.     data(){  
  5.         return {  
  6.             text: '你好,前端自習課',  
  7.             desc: '每日清晨,享受一篇前端優(yōu)秀文章。'  
  8.         }  
  9.     }  
  10. });  
  11. console.log(vm.$data.text)  
  12. vm.$data.text = '頁面數(shù)據(jù)更新成功!'; // 模擬數(shù)據(jù)變化  
  13. console.log(vm.$data.text) 

2. 實現(xiàn)核心入口 vue.js

vue.js 文件是我們實現(xiàn)的整個響應式的入口文件,暴露一個 Vue 類,并掛載全局。 

  1. class Vue {  
  2.     constructor (options = {}) {  
  3.         this.$el = options.el;  
  4.         this.$data = options.data();  
  5.         this.$methods = options.methods;  
  6.         // [核心流程]將普通 data 對象轉(zhuǎn)換為響應式對象  
  7.         new Observer(this.$data);  
  8.         if (this.$el) {  
  9.             // [核心流程]將解析模板的內(nèi)容  
  10.             new Compile(this.$el, this)  
  11.         }  
  12.     }  
  13.  
  14. window.Vue = Vue; 

Vue 類入?yún)橐粋€配置項 option ,使用起來跟 Vue.js 一樣,包括 $el 掛載點、 $data 數(shù)據(jù)對象和 $methods 方法列表(本文不詳細介紹)。

通過實例化 Oberser 類,將普通 data 對象轉(zhuǎn)換為響應式對象,然后判斷是否傳入 el 參數(shù),存在時,則實例化 Compile 類,解析模版內(nèi)容。

總結(jié)下 Vue 這個類工作流程 :

3. 實現(xiàn) observer.js

observer.js 文件實現(xiàn)了 Observer 類,用來將普通對象轉(zhuǎn)換為響應式對象: 

  1. class Observer {  
  2.     constructor (data) {  
  3.         this.data = data;  
  4.         this.walk(data);  
  5.     }  
  6.     // [核心方法]將 data 對象轉(zhuǎn)換為響應式對象,為每個 data 屬性設(shè)置 getter 和 setter 方法  
  7.     walk (data) {  
  8.         if (typeof data !== 'object') return data;  
  9.         Object.keys(data).forEach( key => {  
  10.             this.defineReactive(data, key, data[key])  
  11.         })  
  12.     }  
  13.     // [核心方法]實現(xiàn)數(shù)據(jù)劫持  
  14.     defineReactive (obj, key, value) {  
  15.         this.walk(value);  // [核心過程]遍歷 walk 方法,處理深層對象。  
  16.         const dep = new Dep();  
  17.         Object.defineProperty(obj, key, {  
  18.             enumerable: true, 
  19.              configurable: true,  
  20.             get () {  
  21.                 console.log('[getter]方法執(zhí)行')  
  22.                 Dep.target &&  dep.addSub(Dep.target);  
  23.                 return value  
  24.             },  
  25.             set (newValue) {  
  26.                 console.log('[setter]方法執(zhí)行')  
  27.                 if (value === newValue) return;  
  28.                 // [核心過程]當設(shè)置的新值 newValue 為對象,則繼續(xù)通過 walk 方法將其轉(zhuǎn)換為響應式對象  
  29.                 if (typeof newValue === 'object') this.walk(newValue);  
  30.                 value = newValue 
  31.                 dep.notify(); // [核心過程]執(zhí)行被觀察者通知方法,通知所有觀察者執(zhí)行 update 更新  
  32.             }  
  33.         })  
  34.     }  

相比較第四節(jié)實現(xiàn)的 Observer 類,這里做了調(diào)整:

  •  增加 walk 核心方法,用來遍歷對象每個屬性,分別調(diào)用數(shù)據(jù)劫持方法( defineReactive() );
  •  在 defineReactive() 的 getter 中,判斷 Dep.target 存在才添加觀察者,下一節(jié)會詳細介紹 Dep.target;
  •  在 defineReactive() 的 setter 中,判斷當前新值( newValue )是否為對象,如果是,則直接調(diào)用 this.walk() 方法將當前對象再次轉(zhuǎn)為響應式對象,處理深層對象。

通過改善后的 Observer 類,我們就可以實現(xiàn)將單層或深層嵌套的普通對象轉(zhuǎn)換為響應式對象。

4. 實現(xiàn) watcher.js

這里實現(xiàn)了 Dep 被觀察者類(依賴收集者)和 Watcher 觀察者類。 

  1. class Dep {  
  2.     constructor() {  
  3.         this.subs = [];  
  4.     }  
  5.     addSub(watcher) {  
  6.         this.subs.push(watcher);  
  7.     }  
  8.     notify(data) {  
  9.         this.subs.forEach(sub => sub.update(data));  
  10.     }  
  11.  
  12. class Watcher {  
  13.     constructor (vm, key, cb) {  
  14.         this.vm = vm;   // vm:表示當前實例  
  15.         this.key = key; // key:表示當前操作的數(shù)據(jù)名稱  
  16.         this.cb = cb;   // cb:表示數(shù)據(jù)發(fā)生改變之后的回調(diào)  
  17.         Dep.target = this; // 全局唯一  
  18.         thisthis.oldValue = this.vm.$data[key]; // 保存變化的數(shù)據(jù)作為舊值,后續(xù)作判斷是否更新  
  19.         Dep.target = null 
  20.     } 
  21.      update () {  
  22.         console.log(`數(shù)據(jù)發(fā)生變化!`);  
  23.         let oldValue = this.oldValue;  
  24.         let newValue = this.vm.$data[this.key];  
  25.         if (oldValue != newValue) {  // 比較新舊值,發(fā)生變化才執(zhí)行回調(diào)  
  26.             this.cb(newValue, oldValue);  
  27.         };  
  28.     }  

相比較第四節(jié)實現(xiàn)的 Watcher  類,這里做了調(diào)整:

  •  在構(gòu)造函數(shù)中,增加 Dep.target 值操作;
  •  在構(gòu)造函數(shù)中,增加 oldValue 變量,保存變化的數(shù)據(jù)作為舊值,后續(xù)作為判斷是否更新的依據(jù);
  •  在 update() 方法中,增加當前操作對象 key 對應值的新舊值比較,如果不同,才執(zhí)行回調(diào)。

Dep.target 是當前全局唯一的訂閱者,因為同一時間只允許一個訂閱者被處理。target 指當前正在處理的目標訂閱者,當前訂閱者處理完就賦值為 null 。這里 Dep.target 會在 defineReactive() 的 getter 中使用到。

通過改善后的 Watcher 類,我們操作當前操作對象 key 對應值的時候,可以在數(shù)據(jù)有變化的情況才執(zhí)行回調(diào),減少資源浪費。

4. 實現(xiàn) compile.js

compile.js 實現(xiàn)了 Vue.js 的模版編譯,如將 HTML 中的 {{text}} 模版轉(zhuǎn)換為具體變量的值。

compile.js 介紹內(nèi)容較多,考慮到篇幅問題,并且本文核心介紹響應式原理,所以這里就暫時不介紹 compile.js 的實現(xiàn),在學習的朋友可以到我 Github 上下載該文件直接下載使用即可,地址:

https://github.com/pingan8787/Leo-JavaScript/blob/master/Cute-Gist/Vue/leo-vue-reactive/compile.js

5. 測試代碼

到這里,我們已經(jīng)將第四節(jié)的 demo 改造成簡易版 Vue.js 響應式,接下來打開 index.html 看看效果:

當 index.js 中執(zhí)行到:

  1. vm.$data.text = '我們必須經(jīng)常保持舊的記憶和新的希望。'

頁面便發(fā)生更新,頁面顯示的文本內(nèi)容從“你好,前端自習課”更新成“我們必須經(jīng)常保持舊的記憶和新的希望。”。

到這里,我們的簡易版 Vue.js 響應式原理實現(xiàn)好了,能跟著文章看到這里的朋友,給你點個大大的贊👍

[[377811]]

六、總結(jié)

本文首先通過回顧觀察者模式和 Object.defineProperty() 方法,介紹 Vue.js 響應式原理的核心知識點,然后帶大家通過一個簡單示例實現(xiàn)簡單響應式,最后通過改造這個簡單響應式的示例,實現(xiàn)一個簡單 Vue.js 響應式原理的示例。

相信看完本文的朋友,對 Vue.js 的響應式原理的理解會更深刻,希望大家理清思路,再好好回味下~ 

 

責任編輯:龐桂玉 來源: segmentfault
相關(guān)推薦

2017-08-30 17:10:43

前端JavascriptVue.js

2021-04-14 12:47:50

Vue.jsMJML電子郵件

2023-06-02 16:28:01

2023-06-01 19:19:41

2022-04-17 09:18:11

響應式數(shù)據(jù)Vue.js

2025-09-03 02:46:00

Vue.js響應式變量

2020-06-09 11:35:30

Vue 3響應式前端

2019-07-01 13:34:22

vue系統(tǒng)數(shù)據(jù)

2022-04-16 13:59:34

Vue.jsJavascript

2022-04-25 07:36:21

組件數(shù)據(jù)函數(shù)

2016-11-04 19:58:39

vue.js

2017-07-04 17:55:37

Vue.js插件開發(fā)

2018-04-04 10:32:13

前端JavascriptVue.js

2021-09-27 06:29:47

Vue3 響應式原理Vue應用

2022-04-26 05:55:06

Vue.js異步組件

2022-01-19 22:18:56

Vue.jsVue SPA開發(fā)

2020-09-07 14:40:20

Vue.js構(gòu)建工具前端

2016-11-01 19:10:33

vue.js前端前端框架

2017-07-14 10:10:08

Vue.jsMixin

2017-07-20 11:18:22

Vue.jsMVVMMVC
點贊
收藏

51CTO技術(shù)棧公眾號

日韩精品一区二区免费| 欧美日本在线视频中文字字幕| 日日摸日日碰夜夜爽无码| 亚洲欧美激情在线观看| 亚洲国产精品一区| 亚洲精品福利视频| 无码精品国产一区二区三区免费| 黄色av网站在线看| 男人的天堂久久精品| 日韩在线视频国产| 国产精品v日韩精品v在线观看| 性开放的欧美大片| 国产成人午夜精品影院观看视频 | 一级毛片视频在线| 国产一区二区0| 久久久亚洲精选| 成人午夜福利一区二区| 日韩美女在线| 亚洲一区免费观看| 欧美三日本三级少妇三99| 性色av一区二区三区四区| 在线成人激情| 欧美精品一区二区三区四区| 毛葺葺老太做受视频| 黄网站视频在线观看| 成人午夜视频免费看| 国产97色在线|日韩| 视频国产一区二区| 精品精品精品| 91精品国产色综合久久不卡蜜臀| 欧美不卡在线播放| 91精彩视频在线观看| 国产成人小视频| 国产欧美亚洲精品| 免费观看成人毛片| 欧美aa国产视频| 国产一区二区三区高清在线观看 | a级精品国产片在线观看| 国产成人精品午夜| 国产精品theporn动漫| 青青草91久久久久久久久| 精品久久人人做人人爽| 午夜免费看毛片| 亚洲精品福利电影| 亚洲午夜私人影院| 男同互操gay射视频在线看| 深夜福利在线观看直播| 国产在线播放一区| 国产精品欧美风情| 中文字幕第28页| 国产精品毛片一区二区在线看| 日韩精品福利在线| a级大片免费看| 日韩久久一区| 欧美三级电影在线看| 97超碰青青草| 国产淫片在线观看| 中文字幕第一区第二区| 欧美高清性xxxxhd| 色欲久久久天天天综合网| 国产激情91久久精品导航 | 久久av最新网址| 欧美激情视频一区二区三区不卡 | 亚洲欧美日本在线| 国产成人精品免费看在线播放 | 在线观看欧美日韩电影| 亚洲高清中文字幕| 国产成人在线小视频| 日本欧美在线视频免费观看| 欧美高清在线一区| 奇米视频888战线精品播放| 美国成人毛片| 国产无人区一区二区三区| 欧美激情视频一区二区三区| 亚洲欧洲综合在线| 成人毛片在线观看| 国产九色精品| 午夜视频在线播放| 国产成人精品亚洲777人妖| 91色在线视频| www.成人免费视频| 成人精品一区二区三区四区| 国产精品手机在线| 天堂在线资源8| 91在线porny国产在线看| 久久伊人一区| 国产女主播在线直播| 欧美国产成人精品| 中文字幕人成一区| 欧美巨大xxxx做受沙滩| 五月婷婷另类国产| 青草视频在线观看视频| 国产在线观看www| 欧美性猛交xxx| 日日噜噜夜夜狠狠| 精品久久久久久久久久岛国gif| 69av一区二区三区| 不许穿内裤随时挨c调教h苏绵| 哺乳挤奶一区二区三区免费看 | 黑人操亚洲女人| 91在线看国产| 亚洲无玛一区| 青青草视频在线免费直播| 精品久久久久久久久久久久久久| 国产激情在线观看视频| 四虎视频在线精品免费网址| 日韩精品中午字幕| 黄色片网站免费| 亚洲成人av| 欧美性在线视频| 中文av免费观看| 国产成人精品综合在线观看| 欧美xxxx黑人又粗又长精品| 久cao在线| 亚洲成a人片综合在线| 久久黄色免费看| 老司机亚洲精品一区二区| 亚洲精品一区中文| 天堂网中文在线观看| 亚洲国产美女| 国产一区香蕉久久| 韩国av永久免费| 中文字幕 久热精品 视频在线 | 欧美日韩加勒比精品一区| 日本毛片在线免费观看| 亚洲最大的免费视频网站| 亚洲精品美女视频| 青草影院在线观看| 日韩成人精品在线观看| 亚洲一区二区三区四区在线播放| 天堂在线中文字幕| 亚洲精品写真福利| 亚洲黄色av网址| 琪琪久久久久日韩精品| 国产亚洲aⅴaaaaaa毛片| 久久久久久久久久久网 | 国产99视频在线| 国产日韩视频一区二区三区| 天堂8在线天堂资源bt| 另类一区二区三区| 亚洲精品小视频| 日韩欧美亚洲一区二区三区| 国产麻豆精品在线观看| 天堂√在线观看一区二区| 欧美性受ⅹ╳╳╳黑人a性爽| 欧美综合在线视频| 美女被爆操网站| 99久久亚洲精品| 国产精品久久久久久久久久东京| 色一情一乱一区二区三区| 亚洲另类色综合网站| 亚洲va综合va国产va中文| 国产一区二区亚洲| 性色av香蕉一区二区| www.日本在线观看| 国产夜色精品一区二区av| www.浪潮av.com| 欧美黑人巨大videos精品| 欧美黑人视频一区| av中文字幕第一页| 亚洲精品亚洲人成人网 | 粉嫩13p一区二区三区| 永久久久久久| 亚洲日本中文| 久久国内精品一国内精品| 中文字幕在线播放不卡| 成人免费三级在线| 日韩黄色片在线| 亚洲乱码一区| 欧美另类第一页| 国产日韩一级片| 亚洲精品久久久蜜桃| 中文字幕日韩综合| 久久精品欧美一区| 成人免费网站在线| av在线官网| 日韩区在线观看| 国产真实乱人偷精品视频| 懂色av一区二区三区免费观看| 久久福利一区二区| 中文字幕亚洲在线观看| 欧美激情国产精品| 国产白浆在线观看| 樱桃视频在线观看一区| 日本人添下边视频免费| 久久亚洲欧洲| 国产情侣在线播放| 亚洲国产精品欧美一二99| 亚洲男人在线天堂| 麻豆av福利av久久av| 欧美一区国产| 久久综合五月天| 欧美一区二区三区成人片在线| 欧美性猛交xxxx久久久| 美女三级黄色片| 波多野结衣亚洲一区| 五月婷婷狠狠操| 欧美在线三级| 日韩av一区二区三区美女毛片| 婷婷丁香久久| 欧美重口另类videos人妖| 免费在线观看av网站| 亚洲第一区在线| 亚洲视频在线观看一区二区| 亚洲国产成人av网| 三级影片在线观看| 91一区二区三区在线观看| 国产一级片自拍| 日韩视频在线一区二区三区 | 成人爽a毛片一区二区| 色婷婷国产精品| 加勒比av在线播放| 国产三级欧美三级日产三级99 | 国产欧美一区二区精品婷婷| 精品国产午夜福利在线观看| 老司机精品视频网站| 日韩国产成人无码av毛片| 欧美gayvideo| 欧洲一区二区在线观看| 欧美18xxxx| 国产精品青青草| 高清精品久久| 国产美女91呻吟求| 欧美aa视频| 欧美一级大片视频| av中文字幕在线看| 九色成人免费视频| 成人看片免费| 日韩专区在线播放| 在线日本视频| 一个色综合导航| 九色蝌蚪在线| 亚洲免费人成在线视频观看| 天堂中文网在线| 亚洲国产成人久久综合| 精品国自产在线观看| 欧美日韩不卡在线| 亚洲天堂久久久久| 欧美午夜精品一区二区蜜桃| 国产伦精品一区二区三区视频网站| 亚洲va国产天堂va久久en| 免费在线视频观看| 一区二区久久久久久| 黄色一级片在线免费观看| 亚洲视频免费在线| 放荡的美妇在线播放| 亚洲人成小说网站色在线 | 国产有码一区二区| 日本欧美韩国| 国产精品久久久久久久久久久不卡 | 不用播放器的免费av| 男女男精品网站| 一级淫片在线观看| 国产在线麻豆精品观看| 九九热视频免费| 国产高清无密码一区二区三区| 天天插天天操天天射| 蜜桃视频一区二区三区| 91高清国产视频| 国产精品影视网| 特黄特色免费视频| 白白色亚洲国产精品| 久久久久久久久免费看无码 | 3d动漫精品啪啪| aaa一区二区| 亚洲精品在线一区二区| 天天操天天舔天天干| 亚洲第一区中文字幕| 欧美日本韩国一区二区| 国产亚洲欧美日韩一区二区| 91精彩在线视频| 欧美裸体男粗大视频在线观看| 欧洲成人综合网| 日本国产一区二区三区| 欧美aaaaaaaa| a级国产乱理论片在线观看99| 精品欠久久久中文字幕加勒比| 麻豆av一区二区三区久久| 日本a级不卡| 毛片av在线播放| 国产精品久久久久久久免费软件 | 青青草综合在线| 亚洲九九精品| 日本久久精品一区二区| 国产老妇另类xxxxx| 91精品国产自产| 中文字幕亚洲区| 韩国av免费观看| 欧美日韩国产一级二级| 色婷婷av一区二区三区之e本道| 亚洲人成自拍网站| 在线中文字幕电影| 日本伊人精品一区二区三区介绍| 91嫩草国产线观看亚洲一区二区 | 污污视频在线观看网站| 在线看福利67194| 天堂av最新在线| 国产精品旅馆在线| 中文字幕av一区二区三区四区| 日韩成人在线资源| 欧美日韩亚洲一区| 91最新在线观看| 成+人+亚洲+综合天堂| 黄色av免费播放| 精品久久久久久亚洲国产300 | 精品国产免费一区二区三区四区| 福利成人在线观看| 97人人做人人爱| 精品一区二区三区中文字幕视频 | 911亚洲精选| 国产精品丝袜黑色高跟| 日本五十路女优| 欧美一区二区三区成人| 国产在线视频网址| 91国产视频在线| 亚洲精品影片| 国产三级中文字幕| 免费观看在线综合色| 免费看污黄网站在线观看| 夜夜嗨av一区二区三区中文字幕| 中文字幕av无码一区二区三区| 日韩精品一二三四区| 欧美人与性动交α欧美精品济南到| 91精品久久久久久久久久入口 | 免费在线成人激情电影| 精品一区久久久久久| 狠狠入ady亚洲精品经典电影| 天天操天天干天天做| 国产视频一区二区在线| 六月丁香激情综合| 亚洲激情视频在线播放| 国产精品国精产品一二| 亚洲一区久久久| 一区二区在线| 亚洲一二区在线观看| 成人免费一区二区三区视频| 夜夜嗨aⅴ一区二区三区| 国产亚洲激情在线| 成人看片网页| 欧美最大成人综合网| 久久久精品日韩| 国产人妻人伦精品1国产丝袜| 亚洲伊人色欲综合网| 精品人妻一区二区三区三区四区 | 日本视频一区在线观看| 久久国产精品久久久久久电车| 99久久国产精| 日韩欧美成人区| 人人九九精品| 欧美中文字幕在线播放| 一道本一区二区三区| 日本熟妇人妻xxxxx| 久久久蜜桃精品| 欧美性猛交xxxx乱大交hd| 一本一本久久a久久精品牛牛影视| 欧美成人精品一区二区男人小说| 美女精品国产| 日韩精品一卡二卡三卡四卡无卡| 国产精品av久久久久久无| 欧美自拍偷拍午夜视频| 91九色在线porn| 97免费高清电视剧观看| 亚洲先锋成人| 中文字幕一区三区久久女搜查官| 婷婷中文字幕一区三区| 欧美3p视频在线观看| 国产精品久久久久久久久久久久久久| 成人毛片在线| 午夜不卡福利视频| 亚洲在线视频网站| 视频国产在线观看| 国产精品网站视频| 国产综合自拍| 国产呦小j女精品视频| 欧美系列亚洲系列| 青春草视频在线观看| 欧美日韩国产精品一区二区| 日韩黄色免费网站| 成人免费毛片东京热| 日韩av中文字幕在线播放| 在线成人视屏| 亚洲巨乳在线观看| 高清成人在线观看| 亚洲中文一区二区| 久久综合久久八八| 希岛爱理av免费一区二区| 色婷婷.com| 狠狠干狠狠久久| 国产丝袜在线| 欧美日韩国产一二| 国产激情一区二区三区四区| 毛片在线免费视频| 久久九九国产精品怡红院| 美国十次av导航亚洲入口| 在线免费观看视频黄| 亚洲福利一二三区| 男人资源在线播放| 精品一区二区国产| 国产原创一区二区| 在线免费一区二区|