成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

vue數(shù)據(jù)雙向綁定學(xué)習(xí)筆記。

huashiou / 2422人閱讀

摘要:訂閱者的實(shí)現(xiàn)如下將自己添加到訂閱器的操作緩存自己強(qiáng)行執(zhí)行監(jiān)聽器里的函數(shù)釋放自己到此為止,簡(jiǎn)單版的設(shè)計(jì)完畢,這時(shí)候我們需要將和關(guān)聯(lián)起來(lái),就可以實(shí)現(xiàn)一個(gè)簡(jiǎn)單的雙向數(shù)據(jù)綁定了。同樣使用數(shù)據(jù)劫持。。

什么是雙向綁定

簡(jiǎn)單說(shuō)就是在數(shù)據(jù)和UI之間建立雙向的通信通道,當(dāng)用戶通過(guò)Function改變了數(shù)據(jù),那么這個(gè)改變也會(huì)立即反映到UI上;或者說(shuō)用戶通過(guò)UI的操作也會(huì)隨之引起對(duì)應(yīng)的數(shù)據(jù)變動(dòng)。
Vue是如何實(shí)現(xiàn)雙向數(shù)據(jù)綁定的?數(shù)據(jù)劫持?什么意思呢?太籠統(tǒng)了。與其說(shuō)是數(shù)據(jù)劫持,更應(yīng)該說(shuō)是對(duì)象數(shù)據(jù)對(duì)象的setter和Getter實(shí)現(xiàn)劫持。但是Object.defineProperty僅僅是實(shí)現(xiàn)了對(duì)數(shù)據(jù)的監(jiān)控,后續(xù)實(shí)現(xiàn)對(duì)UI的重新渲染并不是它做的,所以這里還涉及到發(fā)布-訂閱模式;過(guò)程是,當(dāng)監(jiān)控的數(shù)據(jù)對(duì)象被更改后,這個(gè)變更會(huì)被廣播給所有訂閱該數(shù)據(jù)的watcher,然后由該watcher實(shí)現(xiàn)對(duì)頁(yè)面的重新渲染。
步驟:

首先要對(duì)數(shù)據(jù)進(jìn)行劫持,所以我們需要設(shè)置一個(gè)監(jiān)聽器Observer,用來(lái)監(jiān)聽所有的屬性。
如果屬性發(fā)生變化,就需要告訴訂閱者Watcher看是否需要更新。
訂閱者是有很多個(gè),所以我們需要有一個(gè)消息訂閱器Dep來(lái)專門收集這些訂閱者,然后在監(jiān)聽器Observer和訂閱者Watcher之間進(jìn)行統(tǒng)一管理的。
還需要一個(gè)指令解析器Compile,對(duì)每個(gè)節(jié)點(diǎn)元素進(jìn)行掃描和解析,將相關(guān)指令對(duì)應(yīng)初始化成一個(gè)訂閱者Watcher,并替換模板數(shù)據(jù)或者綁定相應(yīng)的函數(shù),此時(shí)當(dāng)訂閱者Watcher接收到相應(yīng)屬性的變化,就會(huì)執(zhí)行相應(yīng)的更新函數(shù),從而更新視圖。
1.實(shí)現(xiàn)一個(gè)監(jiān)聽器Observer,用來(lái)劫持并監(jiān)聽所有屬性,如果有變動(dòng)的,就通知訂閱者。
2.實(shí)現(xiàn)一個(gè)訂閱者Watcher,可以收到屬性的變化通知并執(zhí)行相應(yīng)的函數(shù),從而更新視圖。
3.實(shí)現(xiàn)一個(gè)解析器Compile,可以掃描和解析每個(gè)節(jié)點(diǎn)的相關(guān)指令,并根據(jù)初始化模板數(shù)據(jù)及初始化相應(yīng)的訂閱器。

流程圖如下:

1.實(shí)現(xiàn)一個(gè)Observer

Observer是一個(gè)數(shù)據(jù)監(jiān)聽器,其實(shí)現(xiàn)核心方法就是Object.defineProperty().如果要對(duì)所有屬性都進(jìn)行監(jiān)聽的話,那么可以通過(guò)遞歸方法遍歷所有屬性值,并對(duì)其進(jìn)行Object.defineProperty()處理。

function defineReactive(data,key.val){
    observe(val);//遞歸遍歷所有子屬性
    Obejct.defineProperty(data,key,{
        enumerable:true,
        configurable:true,
        get:function(){
            return val;
        },
        set:function(newVal){
            val = newVal;
            console.log("屬性"+key+"已經(jīng)被監(jiān)聽了")
        }
    })
}
function observe(data){
    if(!data || typeof data !=="object"){
        return;
    }
    Object.keys(data).forEach(function(key){
        defineReactive(data,key,data[key])
    })
}
var library={
    book1:{
        name:""
    },
    book2:""
}
observe(library);
library.book1.name="123";
library.book2="456"

思路分析中,需要?jiǎng)?chuàng)建一個(gè)可以容納訂閱者的消息訂閱器Dep,訂閱器Dep主要負(fù)責(zé)收集訂閱者,然后再屬性變化的時(shí)候執(zhí)行對(duì)應(yīng)訂閱者的更新函數(shù)。所以顯然訂閱者需要有一個(gè)容器,這個(gè)容器就是list,將上面的Observer稍微改造下,植入消息訂閱者:

function defineReactive(data,key,val){
    observe(val)//遞歸遍歷所有子屬性
    var dep = new Dep();
    Object.defineProperty(data,key,{
        enumerable:true,
        configurable:true,
        get:function(){
            if(是否需要添加訂閱者){
                dep.addSub(watcher);//在這里添加一個(gè)訂閱者
            }
            return val;
        },
        set:function(newVal){
            if(val === newVal){
                return;
            }
            val = newVal;
            console.log("屬性"+key+"已經(jīng)被監(jiān)聽了");
            dep.notify();//如果數(shù)據(jù)變化,通知訂閱者
        }
    })
}
function Dep(){
    this.subs = [];
}
Dep.prototype={
    addSub:function(sub){
        this.subs.push(sub);
    },
    notify:function(){
        this.subs.forEach(function(sub){
            sub.update();
        })
    }
}

從代碼上看,我們將訂閱器Dep添加一個(gè)訂閱者設(shè)計(jì)在getter里面,這是為了讓W(xué)atcher初始化進(jìn)行觸發(fā),因此需要判斷是否需要添加訂閱者。在setter函數(shù)里面,如果數(shù)據(jù)變化,就會(huì)去通知所有訂閱者,訂閱者們就會(huì)去執(zhí)行對(duì)應(yīng)的更新函數(shù)。到此,一個(gè)比較完整的Obsever已經(jīng)實(shí)現(xiàn)了,接下來(lái)我們開始設(shè)計(jì)Watcher。

實(shí)現(xiàn)Watcher

訂閱者Watcher在初始化的時(shí)候需要將自己添加進(jìn)訂閱器Dep中,那該如何添加呢?我們已經(jīng)知道監(jiān)聽器Observer是在get函數(shù)執(zhí)行了添加訂閱者Watcher的操作的,所以我們只要在訂閱者Watcher初始化的時(shí)候觸發(fā)對(duì)應(yīng)的get函數(shù)去執(zhí)行添加訂閱者操作即可,那要如何觸發(fā)get的函數(shù)呢?只要獲取對(duì)應(yīng)的屬性值就可以觸發(fā)了,原因就是我們使用了Obejct.defineProperty()進(jìn)行數(shù)據(jù)監(jiān)聽。這里還有一個(gè)細(xì)節(jié)點(diǎn)需要處理,我們只要在訂閱者Watcher初始化的時(shí)候才需要添加訂閱者,所以需要做一個(gè)判斷操作,因此可以在訂閱器上做一下手腳:在Dep.target上緩存下訂閱者,添加成功后再將其去掉就可以了。訂閱者Watcher的實(shí)現(xiàn)如下:

function Watcher(vm,exp,cb){
    this.cb = cb;
    this.vm = vm;
    this.exp = exp;
    this.value = this.get();//將自己添加到訂閱器的操作
}
Watcher.prototype={
    update:function(){
        this.run();
    },
    run:function(){
        var value = this.vm.data[this.exp];
        var oldVal = this.value;
        if(value!==oldVal){
            this.value = value;
            this.cb.call(this.vm,value,oldVal)
        }
    },
    get:function(){
        Dep.target = this;//緩存自己
        var value = this.vm.data[this.exp]//強(qiáng)行執(zhí)行監(jiān)聽器里的get函數(shù)
        Dep.target = null;//釋放自己
        return value;
    }
}

到此為止,簡(jiǎn)單版的Watcher設(shè)計(jì)完畢,這時(shí)候我們需要將Observer和Watcher關(guān)聯(lián)起來(lái),就可以實(shí)現(xiàn)一個(gè)簡(jiǎn)單的雙向數(shù)據(jù)綁定了。
簡(jiǎn)單的例子:




  
  
  
  Document


  

{{name}}

3.實(shí)現(xiàn)Compile

雖然上面已經(jīng)實(shí)現(xiàn)了一個(gè)雙向數(shù)據(jù)綁定的例子,但是整個(gè)過(guò)程都沒(méi)有去解析dom節(jié)點(diǎn),而是直接固定某個(gè)節(jié)點(diǎn)進(jìn)行替換數(shù)據(jù)的,所以接下來(lái)需要實(shí)現(xiàn)一個(gè)解析器Compile來(lái)做解析和綁定工作。解析器Compile實(shí)現(xiàn)步驟:
1.解析模板指令,并替換模板數(shù)據(jù),初始化視圖。
2.將模板指令對(duì)應(yīng)的節(jié)點(diǎn)綁定對(duì)應(yīng)的更新函數(shù),初始化相應(yīng)的訂閱器
為了解析模板,首先需要獲取dom元素,然后對(duì)含有dom元素上含有指令的節(jié)點(diǎn)進(jìn)行處理,因此這個(gè)環(huán)節(jié)需要對(duì)dom操作比較頻繁,所以可以先建一個(gè)fragment片段,將需要解析的dom節(jié)點(diǎn)存入fragment片段里再進(jìn)行處理:

function nodeToFragment(el){
    var fragment = document.createDocumentFragment();
    var child = el.firstChild;
    while(child){
        //將Dom元素移入fragment中
        fragment.appendChild(child);
        child = el.firstChild
    }
    return fragment;
}

接下來(lái)需要遍歷各個(gè)節(jié)點(diǎn),對(duì)含有相關(guān)指定的節(jié)點(diǎn)進(jìn)行特殊處理,這里先處理最簡(jiǎn)單的情況,只對(duì)帶有{{變量}}這種形式的指令進(jìn)行處理。

function compileElement(el){
    var childNodes = el.childNodes;
    var self = this;
    [].slice.call(childNodes).forEach(function(node){
        var reg = /{(.*)}}/;
        var text = node.textContent;
        if(self.isTextNode(node)&®.test(text)){
            self.compileText(node,reg.exec(text)[1])
        }
        if(node.childNodes&&node.childNodes.length){
            self.compileElement(node);//繼續(xù)遞歸遍歷子節(jié)點(diǎn)。
        }
    })
}
function compileText(node,exp){
    var self = this;
    var initText = this.vm[exp];
    this.updateText(node,initText);
    new Watcher(this.vm,exp,function(value){
        self.updateText(node,value);
    })
}
function (node,value){
    node.tetxContent = typeof value =="undefined"?"":value;
}

獲取到最外層節(jié)點(diǎn)后,調(diào)用compileElement函數(shù),對(duì)所有子節(jié)點(diǎn)進(jìn)行判斷,如果節(jié)點(diǎn)是文本節(jié)點(diǎn)且匹配{{}}這種形式指令的節(jié)點(diǎn)就開始進(jìn)行變異處理,編譯處理首先需要初始化視圖數(shù)據(jù),對(duì)應(yīng)上面所說(shuō)的步驟1,接下來(lái)需要生成一個(gè)并綁定更新函數(shù)的訂閱器,對(duì)應(yīng)上面所說(shuō)的步驟2.這樣就完成指令的解析、初始化、編譯三個(gè)過(guò)程,一個(gè)解析器Compile也就可以正常的工作了。為了將解析器Compile與監(jiān)聽器Obsever和訂閱者Watcher關(guān)聯(lián)起來(lái),我們需要再修改一下類SelfVue函數(shù):

function SelfVue(options){
    var self = this;
    this.vm = this;
    this.data = options;
    Object.keys(this.data).forEach(function(key){
        self.proxyKeys(key);
    })
    observe(this.data);
    new Compile(options,this.vm);
    return this;
}

createDocumentFragment:
創(chuàng)建一個(gè)新的空白的文檔片段。
語(yǔ)法:

let fragment = document.createDocumentFragment();

fragment是一個(gè)指向空DocumentFragment對(duì)象的引用。DocumentFragment是DOM節(jié)點(diǎn)。它們不是主dom數(shù)的一部分。通常的用例是創(chuàng)建文檔片段,將元素附加到文檔片段,然后將文檔片段附加到DOM樹。在DOM樹中,文檔片段被其所有的子元素所代替。
因?yàn)槲臋n片段存在于內(nèi)存中,并不在DOM樹中,所以將子元素插入到文檔片段時(shí)不會(huì)引起頁(yè)面回流。因此使用文檔片段通常會(huì)帶來(lái)更好的性能。




  
  
  
  Document


  

{{title}}

{{name}}

代碼分析:

1.new SelfVue() 做了三件事:1.使用Object.definePrototype代理讓訪問(wèn)selfVue的屬性代理為訪問(wèn)selfVue.data的屬性。2.同樣使用Object.definePrototype數(shù)據(jù)劫持。3.new Compile()。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/103006.html

相關(guān)文章

  • 學(xué)習(xí)MVVM及框架的雙向綁定筆記

    摘要:的數(shù)據(jù)劫持版本內(nèi)部使用了來(lái)實(shí)現(xiàn)數(shù)據(jù)與視圖的雙向綁定,體現(xiàn)在對(duì)數(shù)據(jù)的讀寫處理過(guò)程中。這樣就形成了數(shù)據(jù)的雙向綁定。 MVVM由以下三個(gè)內(nèi)容組成 View:視圖模板 Model:數(shù)據(jù)模型 ViewModel:作為橋梁負(fù)責(zé)溝通View和Model,自動(dòng)渲染模板 在JQuery時(shí)期,如果需要刷新UI時(shí),需要先取到對(duì)應(yīng)的DOM再更新UI,這樣數(shù)據(jù)和業(yè)務(wù)的邏輯就和頁(yè)面有強(qiáng)耦合。 在MVVM中,U...

    VioletJack 評(píng)論0 收藏0
  • vue 雙向數(shù)據(jù)綁定的實(shí)現(xiàn)學(xué)習(xí)(一)

    摘要:雙向數(shù)據(jù)綁定簡(jiǎn)言之?dāng)?shù)據(jù)動(dòng)頁(yè)面動(dòng),頁(yè)面動(dòng),數(shù)據(jù)動(dòng)典型的應(yīng)用就是在做表單時(shí)候,輸入框的內(nèi)容改動(dòng)后,跟該輸入框的的值改動(dòng)??垂倬W(wǎng)上的這個(gè)的演示案例雙向數(shù)據(jù)綁定的好處要說(shuō)出這個(gè)好處的時(shí)候,也只有在實(shí)際場(chǎng)景中才能對(duì)應(yīng)的顯示出來(lái)。 前言:本系列學(xué)習(xí)筆記從以下幾個(gè)點(diǎn)展開 什么是雙向數(shù)據(jù)綁定 雙向數(shù)據(jù)綁定的好處 怎么實(shí)現(xiàn)雙向數(shù)據(jù)綁定 實(shí)現(xiàn)雙向數(shù)據(jù)數(shù)據(jù)綁定需要哪些知識(shí)點(diǎn) 數(shù)據(jù)劫持 發(fā)布訂閱模式 ...

    anonymoussf 評(píng)論0 收藏0
  • (原創(chuàng))vue 學(xué)習(xí)筆記

    摘要:菜鳥教程這是一個(gè)屬性其值是字符串菜鳥教程同上這是一個(gè)屬性其值是字符串用于定義的函數(shù),可以通過(guò)來(lái)返回函數(shù)值。它們都有前綴,以便與用戶定義的屬性區(qū)分開來(lái)。 開篇語(yǔ) 我最近學(xué)習(xí)了js,取得進(jìn)步,現(xiàn)在學(xué)習(xí)vue.js.建議新手學(xué)習(xí),請(qǐng)不要用npm的方式(vue-cli,vue腳手架),太復(fù)雜了. 請(qǐng)直接下載vue.js文件本地引入,就上手學(xué)習(xí)吧參照菜鳥教程網(wǎng)站的vue.js教程http://...

    layman 評(píng)論0 收藏0
  • Vue學(xué)習(xí)筆記之一 - 入門

    摘要:而在頁(yè)面中,在之內(nèi)的元素只需寫一個(gè)。但是元素的內(nèi)容被更改之后,控件中的內(nèi)容并不會(huì)同步更新。下面的代碼,在中遍歷實(shí)例中屬性里的每一項(xiàng),并將每個(gè)與綁定。而在定義組件的代碼中,接收傳入的,并在元素中顯示中的字符串。 URL:Introduction - Vue.js 注意 所演示的示例,都是在JS中將Vue實(shí)例綁定至HTML中的指定元素,然后再通過(guò)Vue實(shí)例中data內(nèi)的屬性或者method...

    BLUE 評(píng)論0 收藏0
  • Vue學(xué)習(xí)筆記之一 - 入門

    摘要:而在頁(yè)面中,在之內(nèi)的元素只需寫一個(gè)。但是元素的內(nèi)容被更改之后,控件中的內(nèi)容并不會(huì)同步更新。下面的代碼,在中遍歷實(shí)例中屬性里的每一項(xiàng),并將每個(gè)與綁定。而在定義組件的代碼中,接收傳入的,并在元素中顯示中的字符串。 URL:Introduction - Vue.js 注意 所演示的示例,都是在JS中將Vue實(shí)例綁定至HTML中的指定元素,然后再通過(guò)Vue實(shí)例中data內(nèi)的屬性或者method...

    Ververica 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<