之前的文章《淺析JS中Array物件一些操作方法(附程式碼)》中,給大家了解了JS中Array物件一些操作方法。以下這篇文章給大家了解vue中observer資料雙向綁定原理,夥伴們來看看。
vue
資料雙向綁定原則與簡單的實作
vue
資料雙向綁定原理, 和簡單的實現
去他喵的底層原理,框架內核,老夫寫程式只用Jquery
。
個人覺得,不論是否是長期與之交集,還是應該看下核心的東西。多多了解高人是如何實現的,這樣才能學到更多的知識,才能成長進步。倘若某天被人問起,某種框架內褲,其實現原理,那麼只能是一臉懵逼了。
實作資料綁定的做法有大致如下幾種:
發布者-訂閱者模式(backbone.js
)
髒值檢查(angular.js
)
#資料劫持(vue.js
)
vue.js
則是採用資料劫持結合發布者-訂閱者模式的方式,透過Object.defineProperty()
來劫持各個屬性的setter,getter
,在資料變動時發布訊息給訂閱者,觸發對應的監聽回呼。
假如寫過C#winform
自訂控制項的,我想更能理解之後的邏輯和實作原理
在C
#中當控制項的某個屬性發生了變化,就刷新視圖
priveate int a ; public int A { get { return a; } set { if(a!=value){a = value; Invalidate(); } } } # 当a的值发生变化, 就重绘视图
再來看看Object.defineProperty(obj, prop, descriptor) 方法
位址:https://developer. mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
Object.defineProperty()
方法會直接在一個物件上定義一個新屬性,或修改一個物件的現有屬性,並傳回這個物件。
obj
需要被操作的目標物件
#prop
目標物件需要定義或修改的屬性的名稱。
descriptor
將被定義或修改的屬性的描述符
<strong>descriptor</strong>
configurable
當且僅當該屬性的configurable
為true
時,此屬性描述符才能夠被改變,同時屬性也能從對應的物件上被刪除。預設為false
。
enumerable
當且僅當該屬性的enumerable
為true
時,該屬性才能夠出現在對象的枚舉屬性中。預設為false
。資料描述符同時具有以下可選鍵值:
value
該屬性對應的值。可以是任何有效的JavaScript
值(數值,對象,函數等)。預設為undefined
。
writable
當且僅當該屬性的writable
為true
時,該屬性才能被賦值運算符改變。預設為false
。存取描述符同時具有以下可選鍵值:
get
一個給屬性提供getter
的方法,如果沒有 getter
則為undefined
。此方法傳回值被用作屬性值。預設為undefined
。
set一個給屬性提供setter
的方法,如果沒有setter
則為undefined
。此方法將接受唯一參數,並將該參數的新值指派給該屬性。預設為undefined
。
先來實作一個簡單資料劫持
var A = {}; var a = ""; Object.defineProperty(A, "a", { set: function (value) { a = value; }, get: function () { return "My name is " + a; }, }); A.a = "chuchur"; console.log(A.a); // My name is chuchur
不光是這麼簡單,來看下vue
的程式碼
<div id="app"> <input type="text" v-model="word" /> <p>{{word}}</p> <button v-on:click="sayHi">change model</button> </div> <script> var vm = new Vue({ el: "#app", data: { word: "Hello World!", }, methods: { sayHi: function () { this.word = "Hi, everybody!"; }, }, }); </script>
已經實現的簡單的資料劫持,那麼有多個屬性,就要實現一個資料監聽器Observer
,能夠對資料物件的所有屬性進行監聽,還需要一個訂閱器Dep
來收集這些屬性的變動來通知訂閱者
元素節點的v-model,v-on:click
,就需要實作一個指令解析器Compile
,對每個元素節點的指令進行掃描和解析,根據指令模板替換數據,以及綁定相應的更新函數
最后实现一个订阅者Watcher
,作为连接Observer
和Compile
的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图
大概的流程图如下:
Observer
将需要observe
的数据对象进行递归遍历,包括子属性对象的属性,都加上setter
和getter
这样的话,给这个对象的某个值赋值,就会触发setter
,那么就能监听到了数据变化
// observe function observe(data) { if (data && typeof data === "object") { // 取出所有属性遍历 Object.keys(data).forEach(function (key) { defineReactive(data, key, data[key]); }); } return; } function defineReactive(data, key, val) { observe(val); // 监听子属性 Object.defineProperty(data, key, { enumerable: true, // 可枚举 configurable: false, // 不能再define get: function () { return val; }, set: function (value) { console.log("监听到值变化了: ", val, "==>", value); val = value; }, }); } var A = { fristName: "chuchur", age: 29, }; observe(A); A.fristName = "nana"; //监听到值变化了: chuchur ==> nana A.age = 30; //监听到值变化了: 29 ==> 30
这样就实现了多个属性的监听,接下来就是实现订阅器Dep
,当这些属性变化的时候,触发通知notify
,告诉执行订阅者执行更新函数
//Dep function Dep() { this.subs = []; } Dep.prototype = { addSub: function (sub) { this.subs.push(sub); }, notify: function () { this.subs.forEach(function (sub) { sub.update(); }); }, };
把订阅器植入到监听器里
function defineReactive(data, key, val) { var dep = new Dep() observe(val); //监听子属性 Object.defineProperty(data, key, { set: function(value) { dep.notify() //发出通知, 我被改变了 } }); }
至此,简陋的监听器就实现完成了,接下来继续完成Watcher
。
推荐学习:vue.js教程
以上是解析vue中observer資料雙向綁定原理(程式碼分享)的詳細內容。更多資訊請關注PHP中文網其他相關文章!