實(shí)現(xiàn)雙向數(shù)據(jù)綁定

在上篇文章當(dāng)中,我們實(shí)現(xiàn)了單向數(shù)據(jù)綁定澜躺,那么接下來蝉稳,咱們一步一步來實(shí)現(xiàn)雙向數(shù)據(jù)綁定。

首先最大的問題就是我們?nèi)绾稳ブ纃ata里面的數(shù)據(jù)變化了苗踪,在Vue的實(shí)例化對象的data屬性當(dāng)中颠区,可以查看到該屬性上存在著一個(gè)get和set方法,而這兩個(gè)方法實(shí)際上是通過Object.defineProperty()來實(shí)現(xiàn)數(shù)據(jù)劫持的通铲。

先來實(shí)現(xiàn)一個(gè)簡單的需求,創(chuàng)建一個(gè)簡單的對象器贩。

var Book={

? ? name:"明朝那些事"

}

但是現(xiàn)在我想要在獲取到Book.name的時(shí)候有個(gè)書名號包裹著該怎么辦呢颅夺?這就需要用到上文說到的Object.defineProperty()了。

var Book={}吧黄;

var value="";

Object.defineProperty(Book,"name",{?

? ??get:function(){

? ??????return value;

? ??},

? ??set:function(newValue){

? ??????value="《"+newValue+"》";

? ??}

});



通過Object.defineProperty( )設(shè)置了對象Book的name屬性部服,對其get和set進(jìn)行重寫操作,get就是在讀取name屬性這個(gè)值觸發(fā)的函數(shù)拗慨,set就是在設(shè)置name屬性這個(gè)值觸發(fā)的函數(shù)廓八。而在控制臺輸出的Book對象,乍一看赵抢,和Vue的數(shù)據(jù)長得有點(diǎn)類似剧蹂,說明Vue確實(shí)是通過這種方法來實(shí)現(xiàn)數(shù)據(jù)的劫持的,那么我們就可以實(shí)現(xiàn)一個(gè)監(jiān)聽器observer了烦却。

/*

* Description:監(jiān)聽器

* obj:監(jiān)聽的對象

*/

function observer(obj){

????if(!obj || typeof obj != "object"){

? ?????? return;

? ??}

? ??for(var key in obj){

? ?????? defineReactive(obj,key,obj[key]);

? ??}

}

function defineReactive(obj,key,value){

? ??//遞歸調(diào)用宠叼,監(jiān)聽該對象下面所有子對象的屬性

? ??observer(value);

? ??Object.defineProperty(obj,key,{

? ??????get:function(){

? ??????????return value;

? ??????},

? ??????set:function(newValue){

? ??????????value=newValue;

? ? ? ? }

? ??});

}


有了observer方法,我們就能夠去實(shí)現(xiàn)監(jiān)聽Vue實(shí)例化對象的data屬性值是否發(fā)生了更改其爵,也就是說在Vue類當(dāng)中調(diào)用observer方法即可冒冬,但是現(xiàn)在只是知道了哪個(gè)屬性發(fā)生了變化,卻無法實(shí)時(shí)的更新摩渺,要想實(shí)現(xiàn)這一步简烤,我們先來考慮一個(gè)問題,當(dāng)某一個(gè)屬性值發(fā)生變化的時(shí)候摇幻,是需要將所有綁定該屬性值的節(jié)點(diǎn)的值改為該屬性值乐埠,所以這就用到了發(fā)布和訂閱模式,也就是說囚企,綁定同一個(gè)屬性的每一個(gè)訂閱者都存放在同一個(gè)訂閱器內(nèi)丈咐,如果該屬性值變化了,訂閱器會(huì)逐個(gè)的發(fā)布告知每一個(gè)訂閱者龙宏。(更多詳細(xì)信息請自行百度或參考lk儒家博客)

根據(jù)理解棵逊,很容易的清楚的知道需要一個(gè)訂閱者容器類,該類的實(shí)例化對象必須含有一個(gè)數(shù)組银酗,然后有一個(gè)向該數(shù)組存放訂閱者的方法辆影,以及循環(huán)該數(shù)組通知所有訂閱者更新的方法。

//負(fù)責(zé)收集訂閱者的容器

function Dep(){

? ??this.subs=[];

}

Dep.prototype={

? ??//添加訂閱者的方法

? ??addSub:function(sub){

? ??????this.subs.push(sub);

? ??},

? ??//通知訂閱者的方法

? ??notify:function(){

? ??????this.subs.forEach(function(sub){

? ??????????//調(diào)用訂閱者的update方法讓其進(jìn)行更新

? ??????????sub.update();

? ??????});

? ??}

}


而對于訂閱者黍特,上文也進(jìn)行分析了蛙讥,也很清楚的知道每一個(gè)訂閱者的實(shí)例上都存在著一個(gè)update方法,即更新其內(nèi)容灭衷,而再仔細(xì)想一想次慢,這些訂閱者到底是什么,更新的是什么內(nèi)容呢?是不是每一個(gè)綁定Vue的屬性的節(jié)點(diǎn)都是一個(gè)訂閱者迫像,改變的是該節(jié)點(diǎn)的內(nèi)容劈愚,也就是說,這些訂閱者是在上篇文章當(dāng)中compile的時(shí)候去創(chuàng)建闻妓,需要的參數(shù)值是Vue的實(shí)例化對象菌羽,綁定的該節(jié)點(diǎn)以及綁定的Vue的屬性值。

function Watcher(vm,node,name){

? ??this.vm=vm;

? ??this.node=node;

? ??this.name=name;

? ??//初始化

? ??this.update();

}

Watcher.prototype={

? ??//更新的方法由缆,需要節(jié)點(diǎn)node,vue的實(shí)例化對象,屬性名稱

? ??update:function(){

? ??????if(this.node.nodeType==1 && this.node.nodeName === 'INPUT'){

? ??????????this.node.value=this.vm.data[this.name];

? ??????????return;

? ? ? ? }

? ??????this.node.nodeValue=this.vm.data[this.name];

? ? }

}


而現(xiàn)在我們剩下的問題就是observer和Watcher并沒有關(guān)聯(lián)到一起注祖,細(xì)心的小伙伴可能已經(jīng)發(fā)現(xiàn)了在Watcher類當(dāng)中進(jìn)行了一句初始化操作,而執(zhí)行update方法為什么屬于初始化呢均唉?可以發(fā)現(xiàn)是晨,在update方法當(dāng)中是將this.vm.data[this.name]賦值給節(jié)點(diǎn)內(nèi)容,而this.vm.data[this.name]早已經(jīng)被監(jiān)聽了浸卦,即其會(huì)在賦值之前先執(zhí)行該Vue實(shí)例化對象data屬性的get方法署鸡,所以向訂閱者容器當(dāng)中添加訂閱者的操作就是在監(jiān)聽的get方法當(dāng)中,那么又該如何區(qū)分是否是需要添加的呢限嫌,這里可以在Watcher類當(dāng)中添加一個(gè)標(biāo)識靴庆,例如Dep.target,因?yàn)檫@個(gè)是全局的怒医,所以在每一次操作完后就要對該值釋放炉抒。


修改后的Watcher類


修改后的defineReactive方法

到此為止,整個(gè)Vue的雙向綁定原理基本上說完了稚叹,但是運(yùn)行發(fā)現(xiàn)焰薄,當(dāng)修改輸入框內(nèi)容的時(shí)候,綁定同樣屬性值的內(nèi)容根本就沒有變化扒袖,這是由于沒有給輸入框綁定keyup事件塞茅,在該事件當(dāng)中,只需要將輸入框的內(nèi)容賦值給Vue實(shí)例化對象的data中的綁定屬性即可季率。


給input輸入框綁定keyup事件

最后野瘦,奉上一張邏輯圖,加深理解飒泻,biubiu鞭光!


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市泞遗,隨后出現(xiàn)的幾起案子惰许,更是在濱河造成了極大的恐慌,老刑警劉巖史辙,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件汹买,死亡現(xiàn)場離奇詭異佩伤,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)卦睹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進(jìn)店門畦戒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來方库,“玉大人结序,你說我怎么就攤上這事∽萘剩” “怎么了徐鹤?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長邀层。 經(jīng)常有香客問我返敬,道長,這世上最難降的妖魔是什么寥院? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任劲赠,我火速辦了婚禮,結(jié)果婚禮上秸谢,老公的妹妹穿的比我還像新娘凛澎。我一直安慰自己,他們只是感情好估蹄,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布塑煎。 她就那樣靜靜地躺著,像睡著了一般臭蚁。 火紅的嫁衣襯著肌膚如雪最铁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天垮兑,我揣著相機(jī)與錄音冷尉,去河邊找鬼。 笑死系枪,一個(gè)胖子當(dāng)著我的面吹牛雀哨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嗤无,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼震束,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了当犯?” 一聲冷哼從身側(cè)響起垢村,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嚎卫,沒想到半個(gè)月后嘉栓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宏榕,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年侵佃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了麻昼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,769評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡馋辈,死狀恐怖抚芦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情迈螟,我是刑警寧澤叉抡,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站答毫,受9級特大地震影響褥民,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜洗搂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一消返、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧耘拇,春花似錦撵颊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至挣棕,卻和暖如春译隘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背洛心。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工固耘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人词身。 一個(gè)月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓厅目,卻偏偏與公主長得像,于是被迫代替她去往敵國和親法严。 傳聞我的和親對象是個(gè)殘疾皇子损敷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評論 2 354