轉 vue實現雙向資料繫結之原理及實現篇 vue的雙向繫結原理及實現
轉自:canfoo#!
vue的雙向繫結原理及實現
前言
先上個成果圖來吸引各位:
程式碼: 效果圖:
是不是看起來跟vue的使用方式差不多?接下來就來從原理到實現,從簡到難一步一步來實現這個SelfVue。
本文主要介紹兩大內容:
1. vue資料雙向繫結的原理。
2. 實現簡單版vue的過程,主要實現{{}}、v-model和事件指令的功能。
相關程式碼地址:https://github.com/canfoo/self-vue
vue資料雙向繫結原理
vue資料雙向繫結是通過資料劫持結合釋出者-訂閱者模式的方式來實現的,我們可以先來看一下通過控制檯輸出一個定義在vue初始化資料上的物件是個什麼東西。
程式碼:
var vm = new Vue({ data: { obj: { a: 1 } }, created: function () { console.log(this.obj); } });
結果:
我們可以看到屬性a有兩個相對應的get和set方法,為什麼會多出這兩個方法呢?因為vue是通過Object.defineProperty()來實現資料劫持的。
Object.defineProperty( )是用來做什麼的?它可以來控制一個物件屬性的一些特有操作,比如讀寫權、是否可以列舉,這裡我們主要先來研究下它對應的兩個描述屬性get和set,如果還不熟悉其用法,
在平常,我們很容易就可以打印出一個物件的屬性資料:
var Book = { name: 'vue權威指南' }; console.log(Book.name); // vue權威指南
如果想要在執行console.log(book.name)的同時,直接給書名加個書名號,那要怎麼處理呢?或者說要通過什麼監聽物件 Book 的屬性值。這時候Object.defineProperty( )就派上用場了,程式碼如下:
var Book = {} var name = ''; Object.defineProperty(Book, 'name', { set: function (value) { name = value; console.log('你取了一個書名叫做' + value); }, get: function () { return '《' + name + '》' } }) Book.name = 'vue權威指南'; // 你取了一個書名叫做vue權威指南 console.log(Book.name); // 《vue權威指南》
我們通過Object.defineProperty( )設定了物件Book的name屬性,對其get和set進行重寫操作,顧名思義,get就是在讀取name屬性這個值觸發的函式,set就是在設定name屬性這個值觸發的函式,所以當執行 Book.name = 'vue權威指南' 這個語句時,控制檯會打印出 "你取了一個書名叫做vue權威指南",緊接著,當讀取這個屬性時,就會輸出 "《vue權威指南》",因為我們在get函式裡面對該值做了加工了。如果這個時候我們執行下下面的語句,控制檯會輸出什麼?
console.log(Book);
結果:
乍一看,是不是跟我們在上面列印vue資料長得有點類似,說明vue確實是通過這種方法來進行資料劫持的。接下來我們通過其原理來實現一個簡單版的mvvm雙向繫結程式碼。
思路分析
實現mvvm主要包含兩個方面,資料變化更新檢視,檢視變化更新資料:
關鍵點在於data如何更新view,因為view更新data其實可以通過事件監聽即可,比如input標籤監聽 'input' 事件就可以實現了。所以我們著重來分析下,當資料改變,如何更新檢視的。
資料更新檢視的重點是如何知道資料變了,只要知道資料變了,那麼接下去的事都好處理。如何知道資料變了,其實上文我們已經給出答案了,就是通過Object.defineProperty( )對屬性設定一個set函式,當資料改變了就會來觸發這個函式,所以我們只要將一些需要更新的方法放在這裡面就可以實現data更新view了。
思路有了,接下去就是實現過程了。
前言
先上個成果圖來吸引各位:
程式碼: 效果圖:
是不是看起來跟vue的使用方式差不多?接下來就來從原理到實現,從簡到難一步一步來實現這個SelfVue。
本文主要介紹兩大內容:
1. vue資料雙向繫結的原理。
2. 實現簡單版vue的過程,主要實現{{}}、v-model和事件指令的功能。
相關程式碼地址:https://github.com/canfoo/self-vue
vue資料雙向繫結原理
vue資料雙向繫結是通過資料劫持結合釋出者-訂閱者模式的方式來實現的,我們可以先來看一下通過控制檯輸出一個定義在vue初始化資料上的物件是個什麼東西。
程式碼:
var vm = new Vue({ data: { obj: { a: 1 } }, created: function () { console.log(this.obj); } });
結果:
我們可以看到屬性a有兩個相對應的get和set方法,為什麼會多出這兩個方法呢?因為vue是通過Object.defineProperty()來實現資料劫持的。
Object.defineProperty( )是用來做什麼的?它可以來控制一個物件屬性的一些特有操作,比如讀寫權、是否可以列舉,這裡我們主要先來研究下它對應的兩個描述屬性get和set,如果還不熟悉其用法,請點選這裡閱讀更多用法。
在平常,我們很容易就可以打印出一個物件的屬性資料:
var Book = { name: 'vue權威指南' }; console.log(Book.name); // vue權威指南
如果想要在執行console.log(book.name)的同時,直接給書名加個書名號,那要怎麼處理呢?或者說要通過什麼監聽物件 Book 的屬性值。這時候Object.defineProperty( )就派上用場了,程式碼如下:
var Book = {} var name = ''; Object.defineProperty(Book, 'name', { set: function (value) { name = value; console.log('你取了一個書名叫做' + value); }, get: function () { return '《' + name + '》' } }) Book.name = 'vue權威指南'; // 你取了一個書名叫做vue權威指南 console.log(Book.name); // 《vue權威指南》
我們通過Object.defineProperty( )設定了物件Book的name屬性,對其get和set進行重寫操作,顧名思義,get就是在讀取name屬性這個值觸發的函式,set就是在設定name屬性這個值觸發的函式,所以當執行 Book.name = 'vue權威指南' 這個語句時,控制檯會打印出 "你取了一個書名叫做vue權威指南",緊接著,當讀取這個屬性時,就會輸出 "《vue權威指南》",因為我們在get函式裡面對該值做了加工了。如果這個時候我們執行下下面的語句,控制檯會輸出什麼?
console.log(Book);
結果:
乍一看,是不是跟我們在上面列印vue資料長得有點類似,說明vue確實是通過這種方法來進行資料劫持的。接下來我們通過其原理來實現一個簡單版的mvvm雙向繫結程式碼。
思路分析
實現mvvm主要包含兩個方面,資料變化更新檢視,檢視變化更新資料:
關鍵點在於data如何更新view,因為view更新data其實可以通過事件監聽即可,比如input標籤監聽 'input' 事件就可以實現了。所以我們著重來分析下,當資料改變,如何更新檢視的。
資料更新檢視的重點是如何知道資料變了,只要知道資料變了,那麼接下去的事都好處理。如何知道資料變了,其實上文我們已經給出答案了,就是通過Object.defineProperty( )對屬性設定一個set函式,當資料改變了就會來觸發這個函式,所以我們只要將一些需要更新的方法放在這裡面就可以實現data更新view了。
思路有了,接下去就是實現過程了。