首頁 web前端 js教程 vue響應式原則及依賴收集的介紹 (附程式碼)

vue響應式原則及依賴收集的介紹 (附程式碼)

Mar 26, 2019 am 10:15 AM
javascript

這篇文章帶給大家的內容是關於vue響應式原理及依賴收集的介紹 (附程式碼),有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。

Vue透過設定物件屬性的setter/getter方法來監聽資料的變化,透過getter進行依賴收集,而每個setter方法就是一個觀察者,在資料變更的時候通知訂閱者更新視圖。

將資料data變成可觀察的(observable)

那麼Vue是如何將所有data下面的屬性變成可觀察的呢?

function obsever(value,cb){
    Object.keys(value).forEach((key)=>defineReactive(value,key,value[key],cb))
}
function defineReactive(obj,key,val,cb){
    Object.defineProperty(obj,key,{
        enumerable;true,
        configurable:true,
        get:()=>{
            /*依赖收集*/
            return val;
        },
        set:newVal=>{
            val=newVal;
            cb();
        }
    })
}
class Vue{
    constructor(options){
        this._data = options.data;
        obsever(this._data,options.render)
    }
}

let app = new Vue({
    el:'#app',
    data:{
        text:'text',
        text2:'text2'
    },
    render(){
        console.log('render')
    }
})
登入後複製

為了方便理解,先考慮一個最簡單的情況,不考慮陣列等情況,程式碼如上所示。在initData中會呼叫observe這個函數將Vue的資料設定成observable的。當_data資料改變的時候就會觸發set,對訂閱者進行回呼(這裡是render)。
那麼問題來了,需要對app._data.text操作才會觸發set。為了偷懶,我們需要一個方便的方法透過app.text直接設定就能觸發set對視圖進行重繪。那就需要到代理。

代理

我們可以在Vue的建構子constructor中為data執行一個代理proxy。這樣我們就把data上面的屬性代理到了vm實例上。

_proxy.call(this,options.data);//构造函数
//代理
function _proxy(data){
    const that = this;
    Object.keys(data).forEach(key=>{
        configurable:true,
        enumerable:true,
        get:function proxyGetter(){
            return that._data[key]
        },
        set:function proxySetter(val){
            that._data[key] = val;
        }
    })
}
登入後複製

我們就可以用app.text取代app._data.text了。

為什麼要依賴收集

先看下面這段程式碼

new Vue({
    template:`<p>
                <span>text1:</span>{{text1}}
                <span>text2:</span>{{tetx2}}
              </p>`,
    data:{
        text1:'text1',
        text2:'text2',
        text3:'text3'
    }
})
登入後複製

按照上面的響應式原理中的方法進行綁定則會出現一個問題--text3在實際模板中並沒有被用到,然而當text3的資料被修改時,同樣會觸發text3的setter導致重新執行渲染,這顯然不正確。

先說說Dep

當data上的物件進行修改值的時候會觸發它的setter,那麼取值的時候自然會觸發getter事件,所以我們只要在最開始進行一次render,那麼所有被渲染所依賴的data中的資料就會被getter收集到Dep的subs中去。在對data中的資料進行修改的時候setter只會觸發Dep的subs函數。
定義一個依賴收集類別的Dep。

class Dep{
    constructor(){
        this.subs = [];
    }
    addSub(sub:Watcher){
        this.subs.push(sub)
    }
    removeSub(sub:Watcher){
        remove(this.subs,sub)
    }
    notify(){
        const subs = this.subs.slice()
        for(let i = 0;l=subs.length;i<1;i++){
            subs[i].update()
        }
    }
}
function remove(arr,item){
    if(arr.length){
        const index = arr.indexOf(item)
        if(index>-1){
            return arr.splice(index,1)
        }
    }
}
登入後複製

Watcher

訂閱者,當依賴收集的時候會addSub到sub中,在修改data中資料的時候會觸發dep物件的notify,通知所有Watcher物件去修改對應視圖。

class Watcher {
    constructor (vm, expOrFn, cb, options) {
        this.cb = cb;
        this.vm = vm;

        /*在这里将观察者本身赋值给全局的target,只有被target标记过的才会进行依赖收集*/
        Dep.target = this;
        /*Github:https://github.com/answershuto*/
        /*触发渲染操作进行依赖收集*/
        this.cb.call(this.vm);
    }

    update () {
        this.cb.call(this.vm);
    }
}
登入後複製

開始依賴收集

class Vue {
    constructor(options) {
        this._data = options.data;
        observer(this._data, options.render);
        let watcher = new Watcher(this, );
    }
}

function defineReactive (obj, key, val, cb) {
    /*在闭包内存储一个Dep对象*/
    const dep = new Dep();

    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: ()=>{
            if (Dep.target) {
                /*Watcher对象存在全局的Dep.target中*/
                dep.addSub(Dep.target);
            }
        },
        set:newVal=> {
            /*只有之前addSub中的函数才会触发*/
            dep.notify();
        }
    })
}

Dep.target = null;
登入後複製

將觀察者Watcher實例賦值給全域的Dep.target,然後觸發render操作只有被Dep.target標記過的才會進行依賴收集。有Dep.target的物件會將Watcher的實例push到subs中,在物件被修改觸發setter操作的時候dep會呼叫subs中的Watcher實例的update方法進行渲染。

這篇文章到這裡就已經全部結束了,更多其他精彩內容可以關注PHP中文網的JavaScript影片教學欄位!

以上是vue響應式原則及依賴收集的介紹 (附程式碼)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前 By 尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何使用WebSocket和JavaScript實現線上語音辨識系統 如何使用WebSocket和JavaScript實現線上語音辨識系統 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript實現線上語音辨識系統

WebSocket與JavaScript:實現即時監控系統的關鍵技術 WebSocket與JavaScript:實現即時監控系統的關鍵技術 Dec 17, 2023 pm 05:30 PM

WebSocket與JavaScript:實現即時監控系統的關鍵技術

如何使用WebSocket和JavaScript實現線上預約系統 如何使用WebSocket和JavaScript實現線上預約系統 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript實現線上預約系統

如何利用JavaScript和WebSocket實現即時線上點餐系統 如何利用JavaScript和WebSocket實現即時線上點餐系統 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket實現即時線上點餐系統

簡易JavaScript教學:取得HTTP狀態碼的方法 簡易JavaScript教學:取得HTTP狀態碼的方法 Jan 05, 2024 pm 06:08 PM

簡易JavaScript教學:取得HTTP狀態碼的方法

JavaScript與WebSocket:打造高效率的即時天氣預報系統 JavaScript與WebSocket:打造高效率的即時天氣預報系統 Dec 17, 2023 pm 05:13 PM

JavaScript與WebSocket:打造高效率的即時天氣預報系統

如何在JavaScript中取得HTTP狀態碼的簡單方法 如何在JavaScript中取得HTTP狀態碼的簡單方法 Jan 05, 2024 pm 01:37 PM

如何在JavaScript中取得HTTP狀態碼的簡單方法

javascript如何使用insertBefore javascript如何使用insertBefore Nov 24, 2023 am 11:56 AM

javascript如何使用insertBefore

See all articles