Vue響應式原理與模擬實現

binbin愛學習發表於2019-01-06

Vue響應式實現流程

  • 模板被解析成render函式,繫結資料依賴
  • 設定data中資料的getter和setter特性。屬性變化,重新觸發render

Vue的模板解析

Vue的模板就是HTML加上內建的模板語法,如v-ifv-bind等等

  • 模板最終會轉換成JS程式碼(render函式)
  • 模板具有邏輯,如v-ifv-for,必須通過JS實現

模板

<input id="item" v-model="content"/>
複製程式碼

解析

// 只列出了主要內容
with(this){
    return _c{
        'input',
        {
            // 屬性名
            attrs:{'id':'item'},
            // 指令
            directives:[
                {
                    name:'model',
                    rawName:'v-model',
                    // 對應的資料
                    value:(content)
                }
            ],
            // 繫結的事件
            on:{
                "input" function($event){
                    title = $event.target.value
                }
            }
        }
        
    }
}
複製程式碼
  • with(this)指的是該Vue例項
  • _c (createElement)就是render函式,用來建立虛擬DOM

在模板轉化為JS程式碼的階段,如果使用了v-model,就會在生成的虛擬DOM裡面自動監聽input事件。如果元素的內容被修改,那麼就會觸發input事件,該事件會修改Vue元件例項中對應的資料的值。這樣一來,頁面->資料這個方向的資料繫結就實現了。

Object.defineProperty

給屬性設定getter和setter

var obj = {};
// 設定一箇中間變數,避免遞迴
var _content = '0';
Object.defineProperty(obj,'content',{
    get(){
        console.log('get success')
        return _content;
    },
    set(value){
        console.log('set success')
        _content = value;
    }
})

// obj.content
// get success
// 0
// obj.content = 1
// get success
// 1
// obj.content
// get success
// 1
複製程式碼

所以Vue資料->頁面的資料繫結就是在屬性的setter裡面呼叫render函式。這樣每次資料更新,都會重新渲染頁面

模擬實現

<div>
    <input id="item"/>
</div>
複製程式碼

var item = document.getElementById('item')

var obj = {};
var _content = 0;
Object.defineProperty(obj,'content',{
    get(){
        return _content;
    },
    set(value){
        _content = value;
        // 資料變化,重新渲染頁面資料
        item.value = _content;
    }
})

//渲染初始值
item.value = obj.content

//頁面內容變化,修改繫結資料
item.addEventListener('input',(event)=>{
     obj.content = event.target.value
})

複製程式碼

注:由於Object.defineProperty的效能問題,Vue2.x並沒有實現對陣列和物件屬性變化的檢查。Vue3.x已經使用Proxy來進行雙向繫結,具體可參考
vue3.0 嚐鮮 -- 摒棄 Object.defineProperty,基於 Proxy 的觀察者機制探索

相關文章