成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

實(shí)現(xiàn)一個(gè)簡(jiǎn)單的雙向綁定

elisa.yang / 727人閱讀

摘要:下圖展示了實(shí)現(xiàn)雙向綁定的流程實(shí)現(xiàn)一個(gè)簡(jiǎn)單的雙向綁定雙向綁定最最最初級(jí)進(jìn)階版操作是非常耗時(shí)和好性能,所以在優(yōu)化過(guò)程中先從操作入手。

接觸Vue有一段時(shí)間了,但是對(duì)于其雙向綁定的實(shí)現(xiàn)一直是似懂非懂,今天看到一篇寫(xiě)的比較好的文章 傳送門(mén)1 根據(jù)原作者的指導(dǎo)自己也去實(shí)現(xiàn)了一遍簡(jiǎn)單的 demo (本文的demo均基于Object.defineProperty 實(shí)現(xiàn)數(shù)據(jù)劫持,利用了對(duì)Vue.js實(shí)現(xiàn)雙向綁定的思想)

[注]本文所有圖片均來(lái)自于:傳送門(mén)2

前言 幾種主流的雙向綁定

1.發(fā)布-訂閱模式
2.臟值檢測(cè)

通過(guò)對(duì)比數(shù)據(jù)是否有變更,來(lái)決定是否更新視圖。最簡(jiǎn)單的可以通過(guò)定時(shí)輪詢(xún)?nèi)z測(cè)數(shù)據(jù)的變動(dòng)。當(dāng)然Google不會(huì)這么low, Angular 只有在指定事件觸發(fā)時(shí)進(jìn)入臟值檢測(cè):

DOM事件,比如用戶(hù)輸入文本點(diǎn)擊按鈕等(ng-click)

XHR響應(yīng)事件

瀏覽器 Location 變更

Timer事件

執(zhí)行 $digidt() 或 $apply()

3.數(shù)據(jù)劫持
Vue.js 采用的是 數(shù)據(jù)劫持+發(fā)布/訂閱模式 的方式,通過(guò) Object.defineProperty() 來(lái)劫持各個(gè)屬性的 setter/getter, 在數(shù)據(jù)變動(dòng)時(shí)發(fā)布消息給訂閱者(Wacther), 觸發(fā)相應(yīng)的監(jiān)聽(tīng)回調(diào)。下圖展示了Vue實(shí)現(xiàn)雙向綁定的流程

實(shí)現(xiàn)一個(gè)簡(jiǎn)單的雙向綁定


    
        雙向綁定最最最初級(jí)demo
        
    
    
        

進(jìn)階版demo

DOM操作是非常耗時(shí)和好性能,所以在優(yōu)化過(guò)程中先從DOM操作入手。因?yàn)楸闅v解析過(guò)程中有多次DOM操作,為了提高性能和效率,需要一種方法來(lái)避免對(duì)DOM元素的直接封裝操作。在Vue使用 DocumentFragment 作為替代容器。
DocumentFragment 接口表示一個(gè)沒(méi)有父級(jí)文件的最小文檔對(duì)象。它被當(dāng)做一個(gè)輕量版本的Document 使用。所以使用 DocumentFragment 代替DOM直接處理,可以提高性能和速度。

封裝DOM節(jié)點(diǎn)為 DocumentFragment
//將傳入 node 的子節(jié)點(diǎn)進(jìn)行劫持,經(jīng)過(guò)處理后重新掛載回目標(biāo)節(jié)點(diǎn)
function convertNode(node,vm){
    var fragment = document.createDocumentFragment(),
        child
    while(child = node.firstChild){
        //將原生節(jié)點(diǎn)拷貝到 fragment,并刪除之前的child節(jié)點(diǎn)
        fragment.appendChild(child)
    }
    return fragment
}

var dom = convertNode(document.getElementById("app"))
document.getElmentById("app").appendChild(dom)
實(shí)現(xiàn)Complie解析模板指令

Complie 主要做的事情就是解析模板指令,將模板中的變量替換為數(shù)據(jù)。所以要遍歷整個(gè)DOM樹(shù),進(jìn)行掃描解析編譯,調(diào)用對(duì)應(yīng)的指令渲染函數(shù)進(jìn)行渲染,并調(diào)用對(duì)應(yīng)的指令更新函數(shù)進(jìn)行綁定

{{text}}
function convertNode(node,vm){
    //...
    while(child = node.firstChild){
        Compile(child,vm)
        fragment.appendChild(child)
    }
    return fragment
}
function Compile(node,vm){
    var reg = /{{(.*)}}/
    if(node.nodeType===1){  
        var attr = node.attributes  //對(duì)所有屬性進(jìn)行解析
        for(var i=0;i
ViewModel 層向 View 層的數(shù)據(jù)綁定

接下來(lái)實(shí)現(xiàn)一個(gè) Xin 構(gòu)造器,通過(guò) Compile 來(lái)解析模板指令,通過(guò) Observer 監(jiān)聽(tīng)屬性數(shù)據(jù)的變化實(shí)現(xiàn) Model 層向 View 層的數(shù)據(jù)綁定

function Xin(options){
    this.data = options.data
    Observer(this.data,this)
    var id = options.el
    var dom = convertNode(document.getElementById(id),this)
    document.getElementById(id).appendChild(dom)
}

新建一個(gè) vm 實(shí)例來(lái)測(cè)試一下 Model --> View 的綁定情況

var vm = new Xin({
    el:"app",
    data:{
        text:"Hello MVVM"
    }
})
View 層向 viewModel 層的數(shù)據(jù)綁定

實(shí)際上,在 Observer 中我們已經(jīng)通過(guò) 數(shù)據(jù)劫持 實(shí)現(xiàn)了監(jiān)聽(tīng)每個(gè)數(shù)據(jù)的變化,在控制臺(tái)打印 console.log(val) 就可以實(shí)時(shí)看到數(shù)據(jù)的變化。所以接下來(lái)實(shí)現(xiàn)的關(guān)鍵就是怎么用監(jiān)聽(tīng)到的數(shù)據(jù)去更新視圖。
在這里,我們?nèi)?shí)現(xiàn)一個(gè) Wacther 可以將它理解為觀(guān)察者 ,他的作用是能夠接收從 Observer 發(fā)過(guò)來(lái)的屬性變動(dòng)通知, 然后根據(jù)屬性的變動(dòng)更新視圖 update。

在監(jiān)聽(tīng)過(guò)程中,為所有的 data 屬性生成一個(gè)主題對(duì)象 Dep,Dep中包含需要維護(hù)的觀(guān)察者列表。每當(dāng)主題對(duì)象狀態(tài)發(fā)生變化時(shí),其相關(guān)依賴(lài)都會(huì)得到通知,并且被自動(dòng)更新(數(shù)據(jù)變動(dòng)會(huì)觸發(fā)notify,再調(diào)用訂閱者的update() 方法)

function Dep(){
    this.subs=[]    //訂閱者隊(duì)列
}
Dep.prototype={
    addSub:function(sub){
        this.subs.push(sub)
    },
    notify:function(){
        this.subs.forEach(function(sub){
            sub.update()
        })
    }
}

funcion Watcher(vm,node,bindName){
    //將全局Dep.target設(shè)置為當(dāng)前頁(yè)面元素node
    Dep.target = this
    //完成watcher的初始化
    this.name = bindName
    this.node = node
    this.vm = vm

    this.update()    //初次綁定時(shí)進(jìn)行更新
    Dep.target = null    //保證Dep.target唯一
}

Watcher.prototype = {
    get:function(){
        this.value = this.vm.data[this.name]
    },
    update:function(){
        this.get()
        this.node.nodeValue = this.value
    }
}

function Observer(obj,vm){
    //...
    Object.defineProperty(obj,prop,{
        get:function(){...},
        set:function(newVal){
            if(val == newVal) return
            val = newVal
            //data屬性被修改,由dep觸發(fā)view層更新
            dep.notify()
        }
    })
}

考慮這樣一個(gè)問(wèn)題,什么時(shí)候會(huì)有雙向綁定? viewModel --> view 可能會(huì)發(fā)生在所有類(lèi)型的DOM節(jié)點(diǎn)上,而 view --> viewModel 只能發(fā)生在 input, select, textarea 等交互控件上。所以將文本節(jié)點(diǎn)包裝成 Watcher , 添加相關(guān)元素的觀(guān)察者列表中,Watcher 負(fù)責(zé)更新頁(yè)面元素

function Compile(node,vm){
    //...
    if(node.nodeType ===3){    //文本節(jié)點(diǎn)類(lèi)型
        if(reg.test(node.nodeValue)){
            var bindName = RegExp.$1.trim()
            new Watcher = (vm,node,bindName)    //為該頁(yè)面元素node生產(chǎn)watcher
        }
    }
}
更新

本文中實(shí)現(xiàn)模板渲染的方法借鑒了 Vue 1.x 中實(shí)現(xiàn)模板渲染的方法。
Vue 2.x 模板渲染 方法借鑒React 中的 VirtualDOM,基于 VirtualDOM。 Vue 2.x 還支持服務(wù)端渲染SSR

資料參考

1.https://github.com/DMQ/mvvm#_2

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/91898.html

相關(guān)文章

  • 最近老是有兄弟問(wèn)我,Vue雙向綁定原理,以及簡(jiǎn)單原生js寫(xiě)出來(lái)實(shí)現(xiàn),我就來(lái)一個(gè)簡(jiǎn)單雙向綁定,

    摘要:廢話(huà)不多說(shuō)直接看效果圖代碼很好理解,但是在看代碼之前需要知道雙向綁定的原理其實(shí)就是基于實(shí)現(xiàn)的雙向綁定官方傳送門(mén)這里我們用官方的話(huà)來(lái)說(shuō)方法會(huì)直接在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)對(duì)象的現(xiàn)有屬性,并返回這個(gè)對(duì)象。 廢話(huà)不多說(shuō)直接看效果圖 showImg(https://segmentfault.com/img/bVbiYY5?w=282&h=500); 代碼很好理解,但是在看代碼之前...

    zhangfaliang 評(píng)論0 收藏0
  • 最近老是有兄弟問(wèn)我,Vue雙向綁定原理,以及簡(jiǎn)單原生js寫(xiě)出來(lái)實(shí)現(xiàn),我就來(lái)一個(gè)簡(jiǎn)單雙向綁定,

    摘要:廢話(huà)不多說(shuō)直接看效果圖代碼很好理解,但是在看代碼之前需要知道雙向綁定的原理其實(shí)就是基于實(shí)現(xiàn)的雙向綁定官方傳送門(mén)這里我們用官方的話(huà)來(lái)說(shuō)方法會(huì)直接在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)對(duì)象的現(xiàn)有屬性,并返回這個(gè)對(duì)象。 廢話(huà)不多說(shuō)直接看效果圖 showImg(https://segmentfault.com/img/bVbiYY5?w=282&h=500); 代碼很好理解,但是在看代碼之前...

    aristark 評(píng)論0 收藏0
  • JavaScript數(shù)據(jù)雙向綁定簡(jiǎn)單演示

    摘要:對(duì)于前端,有時(shí)候需要實(shí)現(xiàn)視圖層和數(shù)據(jù)層的雙向綁定例如當(dāng)前流行的各種框架和類(lèi)庫(kù)。為代表前端數(shù)據(jù)劫持。參考資料實(shí)現(xiàn)數(shù)據(jù)雙向綁定的三種方式談?wù)勚械碾p向數(shù)據(jù)綁定非常簡(jiǎn)單的雙向數(shù)據(jù)綁定框架三 對(duì)于前端,有時(shí)候需要實(shí)現(xiàn)視圖層和數(shù)據(jù)層的雙向綁定(two-way-binding), 例如當(dāng)前流行的各種框架和類(lèi)庫(kù):Vue.js、Angular.js、React.js。 然而,他們最原始的實(shí)現(xiàn)方式其實(shí)都相...

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

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

0條評(píng)論

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