從Object.defineProperty看vue響應式資料繫結最簡單的實現

童話鎮發表於2019-01-19

vue響應式資料繫結最簡單的實現

原文在我的github前端部落格,地址[github.com/dzfrontend/…],歡迎訂閱...

vue響應式資料繫結:當資料發生改變,檢視自動更新

原理

把一個普通的js物件傳給vue例項的data選項,vue講遍歷此物件的所有屬性,使用Object.defineProperty把這些屬性轉化成getter和setter,vue內部會對資料進行劫持,在屬性被訪問和修改的時候進行通知。

Object.defineProperty

作用:

在一個物件上定義一個新屬性,或者修改一個物件的現有屬性。

語法:

Object.defineProperty(obj, obj.key, {
 // 資料描述
    value: 該屬性對應的值 預設undefined,
    writable: 該屬性是否可以被重寫 預設false,
    enumerable: 該屬性是否可以被列舉(是否可以被for-in遍歷) 預設false,
    configurable: 該屬性是否可以被刪除 預設false,
 // 訪問器描述
    get: function(){
    }
    set: function(newValue) {
    }
})

複製程式碼

相容性:

屬於es5中的方法,但是不相容ie8,這也是vue不相容ie8的原因。

實現最簡單的響應式資料繫結

在傳統的dom操作方式中,資料發生變化,頁面不會自動更新變化,需要再次進行dom操作才能讓檢視發生變化。

<div id="app">
    <button id="btn">改變資料</button>
    <h5 id="title"></h5>
</div>
<script>
    var data = {
        title: '資料'
    }
    var title = document.getElementById('title');
    var btn = document.getElementById('btn');

    title.innerHTML = data.title;
    btn.onclick = function() {
        data.title = '資料發生變化';
        title.innerHTML = data.title; // 再次改變dom節點的innerHTML
    }
</script>

複製程式碼

上面例子中,data.title繫結到了id為title的dom節點中,當點選button的時候,改變data.title,需要重新改變dom,檢視才會發生變化。

要想實現vue響應式資料繫結,需要用到Object.defineProperty, 使用資料的時候,進行資料劫持,把屬性轉成訪問器的方式,然後vue處理檢視更新。

<div id="app">
    <button id="btn">改變資料</button>
    <h5 id="title"></h5>
</div>
<script>
    var data = {
        title: '資料'
    }
    
    // 資料劫持
    function observer(obj) {
        Object.keys(obj).forEach(function(item){
            defineReactive(obj, item, obj[item]);
        })
    }
    function defineReactive(obj, key, value) {
        Object.defineProperty(obj, key, {
            get() {
                return value;
            },
            set(newValue) {
                value = newValue;
                title.innerHTML = value; // 更新檢視,vue內部處理,這裡是簡寫
            }
        })
    }
    
    observer(data);

    var title = document.getElementById('title');
    var btn = document.getElementById('btn');

    title.innerHTML = data.title;
    // 更新檢視,直接運算元據,不用進行dom操作
    btn.onclick = function() {
        data.title = '資料發生變化';
    }
</script>

複製程式碼

上面例子中,observer(data)對資料data裡面的每一個屬性進行劫持,data裡面屬性title的值發生改變時,在Object.defineProperty裡的setter會獲取到發生改變的值,vue內部然後進行檢視更新;

當點選button,只需要改變data.title而不用進行dom操作,vue內部會自動處理檢視更新。

full examples at here.

原文在我的github前端部落格,地址[github.com/dzfrontend/…],歡迎訂閱...

相關文章