Object.defineProperty實(shí)現(xiàn)視圖數(shù)據(jù)綁定demo

vue.js 最核心的功能有兩個(gè),一個(gè)是響應(yīng)式數(shù)據(jù)綁定,二是組件系統(tǒng)。
今天講講雙向數(shù)據(jù)綁定的實(shí)現(xiàn)
vue.js和avalon.js是通過Object.defineProperty實(shí)現(xiàn)雙向數(shù)據(jù)綁定的

1、簡單用法如下

    var a= {}
    Object.defineProperty(a,"b",{
        value:123
    })
    console.log(a.b);//123

2、具體參數(shù)看下面代碼、其中有比較關(guān)鍵的setget

var obj = {}; // Creates a new object 創(chuàng)造對(duì)象
Object.defineProperty(obj, "hello", {
         get: function () {return sth},
         set: function (val) {/* do sth */}
})
obj.hello // 可以像普通屬性一樣讀取訪問器屬性
訪問器屬性的"值"比較特殊,讀取或設(shè)置訪問器屬性的值,實(shí)際上是調(diào)用其內(nèi)部特性:get和set函數(shù)。
obj.hello // 讀取屬性,就是調(diào)用get函數(shù)并返回get函數(shù)的返回值
obj.hello = "abc" // 為屬性賦值,就是調(diào)用set函數(shù),賦值其實(shí)是傳參

好了現(xiàn)在簡單講下如何實(shí)現(xiàn)數(shù)據(jù)視圖綁定

極簡雙向綁定的實(shí)現(xiàn)一

    <input type="text" id="test">
    <p id="test2"></p>

<script type="text/javascript">
    var obj = {};
    Object.defineProperty(obj, "test", {
        set: function (newVal){
            document.getElementById("test2").innerHTML = newVal;
        }
    })

    document.addEventListener('keyup', function(e) {
        obj.test = e.target.value;    // input輸入的值作為obj的“動(dòng)態(tài)屬性值”,賦值給p
    })
</script>

此例實(shí)現(xiàn)的效果是:隨文本框輸入文字的變化,span 中會(huì)同步顯示相同的文字內(nèi)容;在js或控制臺(tái)顯式的修改 obj.hello 的值,視圖會(huì)相應(yīng)更新。這樣就實(shí)現(xiàn)了 model => view 以及 view => model 的雙向綁定。

![vue實(shí)現(xiàn)雙向綁定的原理]554AJ.png](http://upload-images.jianshu.io/upload_images/1627906-f6bd2f7554a1e143.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

極簡雙向綁定的實(shí)現(xiàn)二

HTML
    <div>
        <p>你好,<span id='nickName'></span></p>
        <div id="introduce"></div>
    </div>
    <button id="btn">點(diǎn)擊</button>
JS
var userInfo = {};
Object.defineProperty(userInfo, "nickName", {
    get: function(){
        return document.getElementById('nickName').innerHTML;
    },
    set: function(nick){
        document.getElementById('nickName').innerHTML = nick;
    }
});
Object.defineProperty(userInfo, "introduce", {
    get: function(){
        return document.getElementById('introduce').innerHTML;
    },
    set: function(introduce){
        document.getElementById('introduce').innerHTML = introduce;
    }
})

document.getElementById('btn').onclick = function(){
    userInfo.nickName = "xxx";
    userInfo.introduce = "我是xxx,我來自杭州,..."
}
0
1

三、分解任務(wù)
上述示例僅僅是為了說明原理。我們最終要實(shí)現(xiàn)的是:


0

1

首先將該任務(wù)分成幾個(gè)子任務(wù):
   1、輸入框以及文本節(jié)點(diǎn)與 data 中的數(shù)據(jù)綁定
   2、輸入框內(nèi)容變化時(shí),data 中的數(shù)據(jù)同步變化。即 view => model 的變化。
   3、data 中的數(shù)據(jù)變化時(shí),文本節(jié)點(diǎn)的內(nèi)容同步變化。即 model => view 的變化。
要實(shí)現(xiàn)任務(wù)一,需要對(duì) DOM 進(jìn)行編譯,這里有一個(gè)知識(shí)點(diǎn):DocumentFragment

DocumentFragment

DocumentFragment(文檔片段)可以看作節(jié)點(diǎn)容器,它可以包含多個(gè)子節(jié)點(diǎn),當(dāng)我們將它插入到 DOM 中時(shí),只有它的子節(jié)點(diǎn)會(huì)插入目標(biāo)節(jié)點(diǎn),所以把它看作一組節(jié)點(diǎn)的容器。使用 DocumentFragment 處理節(jié)點(diǎn),速度和性能遠(yuǎn)遠(yuǎn)優(yōu)于直接操作 DOM。Vue 進(jìn)行編譯時(shí),就是將掛載目標(biāo)的所有子節(jié)點(diǎn)劫持(真的是劫持,通過 append 方法,DOM 中的節(jié)點(diǎn)會(huì)被自動(dòng)刪除)到 DocumentFragment 中,經(jīng)過一番處理后,再將 DocumentFragment 整體返回插入掛載目標(biāo)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容