摘要:雙向數據綁定可算是前端領域經久不衰的熱詞,不管是前端開發還是面試都會有所涉及。因此,中的挺身而出,拯救了中對數組數據處理的不足。有興趣的朋友請期待筆者的下一篇博客,討論下用實現雙向數據綁定。
雙向數據綁定可算是前端領域經久不衰的熱詞,不管是前端開發還是面試都會有所涉及。而且不同的框架也想盡一切辦法去實現這一特性,比如:
Knockout / Backbone --- 發布-訂閱模式
Angular --- ‘臟檢查’
Vue --- "Object.defineProperty"
那么雙向數據綁定到底是什么?沒圖說個卵,直接上圖
簡單的說就是在數據和UI之間建立雙向的通信通道,當用戶通過Function改變了數據,那么這個改變也會立即反應到UI上;或者說用戶通過UI的操作,那么這些操作也會隨之引起對應的數據變動。emmmmmm...沒毛病!
既然本文標題是討論Object.defineProperty,那么筆者就把當前火熱的到Boom的國產框架:Vue.js 請出來,然后在了解完她實現雙向數據綁定的原理之后,我們著手實現一個抽象派的雙向數據綁定。那么那位朋友就說了,什么叫 抽象派 ?我估計吧,可能就是馬(Vue)和馬骨架的區別吧,TAT...
在介紹Vue的雙向數據綁定之前,筆者還想多叨叨幾句,如果某一天有人問你:Vue是如何實現雙向數據綁定的? 姑且先在這里停頓下,思考下這個問題的答案...................
或許有朋友會脫口而出“數據劫持”,說的沒錯!的確就是“數據劫持”,但是還不夠充分和不夠精確。筆者在這里也談下自己的一點點所見所聞所想:
不夠精確:與其說是 數據劫持,更應該說是對數據對象的Setter和Getter實現的劫持。
不夠充分:為什么說不夠充分?是因為 Object.defineProperty 僅僅是實現了對數據的監控,后續實現對UI的重新渲染并不是它做的,所以這里還涉及到 發布-訂閱模式(有興趣的朋友戳這里);過程是,當監控的數據對象被更改后,這個變更會被廣播給所有訂閱該數據的watcher,然后由該 watcher實現對頁面的重新渲染。
下面進入正題,一起了解下Vue實現雙向數據綁定的原理,果斷上圖:
首先,Vue的Compile模塊會對Vue的 template 代碼進行編譯解析并生成一系列的watcher,也可以稱之為“更新函數”,它負責把變更后的相關數據重新渲染到指定的地方。舉個栗子:
Compile會解析出 v-moel 這個指令并且生成 watcher 并連接數據中的 message 和當前這個Dom對象,一旦收到這個message被變更的通知,watcher就會根據變更對這個Dom進行重新渲染。
當然一個頁面或者一個項目中肯定有很多watcher,因此Vue使用了Dep這個對象來存儲每一個watcher,當數據發生變更,Observer會調用Dep的notify方法以通知所有訂閱了該數據的watcher,讓它們醒醒該干活了...
Vue的雙向數據綁定也說得差不多了,下面就開始順著這個思路著手寫一個吧,畢竟說得多不如code來得好啊!!!具體的實現效果如下,Let‘s do it
不知道為什么GIF上傳不了,所以只能將就用圖片了,QAQ....
功能就用文字解釋下:
第一個行的 title 0 直接顯示的是數據,以便觀察;我們可以在輸入框中輸入任何int, 然后點擊“加”可以實現對數值的 +1 操作,同時輸入框的數值和 title 也會隨之變化;當然,通過輸入數值,title也會跟著變化。
首先把Html代碼呈上來:
Object.defineProperty實現雙向綁定
然后開始一步一步在index.js里寫代碼吧
1) 首先我們先定義一個數據源
//數據源 let vm = { value: 0 }
2) 然后定義一個Dep,用于存儲watcher
//用于管理watcher的Dep對象 let Dep = function () { this.list = []; this.add = function(watcher){ this.list.push(watcher) }, this.notify = function(newValue){ this.list.forEach(function (fn) { fn(newValue) }) } };
3) 模擬Compile出來的watchers,該demo涉及到兩個地方的重新render,一個是title,另一個是輸入框。所以寫兩個watcher,然后存入Dep
// 模擬compile,通過對Html的解析生成一系列訂閱者(watcher) function renderInput(newValue) { let el = document.getElementById("inp"); if (el) { el.value = newValue } } function renderTitle(newValue) { let el = document.getElementById("h1"); if (el) { el.innerHTML = newValue } } //將解析出來的watcher存入Dep中待用 let dep = new Dep(); dep.add(renderInput); dep.add(renderTitle)
4) 使用 Object.defineProperty 定義一個Observer
function observer(vm, key, value) { Object.defineProperty(vm, key, { enumerable: true, configurable: true, get: function () { console.log("Get"); return value }, set: function (newValue) { if (value !== newValue) { value = newValue console.log("Update") //將變動通知給相關的訂閱者 dep.notify(newValue) } } }) }
5) 再將頁面使用的兩個方法寫出來。(Vue使用的是指令對事件進行綁定,但是本文不涉及指令,所以用最原始的方法綁定事件)
//頁面引用的方法 function inputChange(ev) { let value = Number.parseInt(ev.target.value); vm.value = (Number.isNaN(value)) ? 0 : value; } function btnAdd() { vm.value = vm.value + 1; }
主要的代碼都寫好后,下面第一件事就是初始化:
//數據初始化方法 function initMVVM(vm) { Object.keys(vm).forEach(function (key) { observer(vm, key, vm[key]) }) } //初始化數據源 initMVVM(vm) //初始化頁面,將數據源渲染到UI dep.notify(vm.value);
這樣一個簡單的基于 Object.defineProperty 的雙向數據綁定就完成了。看完的朋友有沒有對雙向數據綁定有了更多的理解了呢?如果沒有理解的話,可以將代碼復制到本地,然后循著代碼再運行下,或許能容易理解。當然這里的代碼并不高深,只是從淺層去談論了雙向數據綁定,所以有不足或者表達錯誤的地方,煩請各位朋友多多指正。
這里是源碼,由于放不了動圖,所以有興趣的小伙伴可以拿下來
最后還是補充一句,Object.defineProperty雖然好用,但并不是無懈可擊的,它對數組數據的處理并沒有想象中的好甚至表現很差,因此Vue團隊專門為Vue中的數組類型編寫了額外的方法以實現對數組的正確監控
。因此,ES6中的Proxy挺身而出,拯救了ES5 中 Object.defineProperty對數組數據處理的不足。有興趣的朋友請期待筆者的下一篇博客,討論下用Proxy實現雙向數據綁定。
咱們下期再見!!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/95800.html
摘要:廢話不多說直接看效果圖代碼很好理解,但是在看代碼之前需要知道雙向綁定的原理其實就是基于實現的雙向綁定官方傳送門這里我們用官方的話來說方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性,并返回這個對象。 廢話不多說直接看效果圖 showImg(https://segmentfault.com/img/bVbiYY5?w=282&h=500); 代碼很好理解,但是在看代碼之前...
摘要:廢話不多說直接看效果圖代碼很好理解,但是在看代碼之前需要知道雙向綁定的原理其實就是基于實現的雙向綁定官方傳送門這里我們用官方的話來說方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性,并返回這個對象。 廢話不多說直接看效果圖 showImg(https://segmentfault.com/img/bVbiYY5?w=282&h=500); 代碼很好理解,但是在看代碼之前...
摘要:當我們的視圖和數據任何一方發生變化的時候,我們希望能夠通知對方也更新,這就是所謂的數據雙向綁定。返回值返回傳入函數的對象,即第一個參數該方法重點是描述,對象里目前存在的屬性描述符有兩種主要形式數據描述符和存取描述符。 前言 談起當前前端最熱門的 js 框架,必少不了 Vue、React、Angular,對于大多數人來說,我們更多的是在使用框架,對于框架解決痛點背后使用的基本原理往往關注...
摘要:雙向數據綁定的核心和基礎是其內部真正參與數據雙向綁定流程的主要有和基于和發布者訂閱者模式,最終實現數據的雙向綁定。在這里把雙向數據綁定分為兩個流程收集依賴流程依賴收集會經過以上流程,最終數組中存放列表,數組中存放列表。 Vue雙向數據綁定的核心和基礎api是Object.defineProperty,其內部真正參與數據雙向綁定流程的主要有Obderver、Dep和Watcher,基于d...
閱讀 1862·2023-04-25 23:28
閱讀 568·2023-04-25 22:49
閱讀 2249·2021-09-27 13:34
閱讀 5196·2021-09-22 15:09
閱讀 3612·2019-08-30 12:52
閱讀 2745·2019-08-29 15:26
閱讀 663·2019-08-29 11:12
閱讀 2194·2019-08-26 12:24