成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

【Vue原理】Watch - 源碼版

Hancock_Xu / 1551人閱讀

摘要:寫(xiě)文章不容易,點(diǎn)個(gè)贊唄兄弟專(zhuān)注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于版本如果你覺(jué)得排版難看,請(qǐng)點(diǎn)擊下面鏈接或者拉到下面關(guān)注公眾號(hào)也可以吧原理源碼版今天繼續(xù)探索源碼,廢話不

寫(xiě)文章不容易,點(diǎn)個(gè)贊唄兄弟
專(zhuān)注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧
研究基于 Vue版本 【2.5.17】

如果你覺(jué)得排版難看,請(qǐng)點(diǎn)擊 下面鏈接 或者 拉到 下面關(guān)注公眾號(hào)也可以吧

【Vue原理】Watch - 源碼版

今天繼續(xù)探索 Watch 源碼,廢話不多說(shuō)了

帶著我的幾個(gè)疑問(wèn)開(kāi)始

1、什么時(shí)候初始化

2、怎么確定監(jiān)聽(tīng)哪些值

3、深度監(jiān)聽(tīng)怎么回事

4、怎么觸發(fā)我的函數(shù)

這些問(wèn)題的答案會(huì)摻雜在源碼的解析中,我發(fā)現(xiàn)這幾篇的寫(xiě)作套路都差不多.....

也可以看查一下我的白話版

什么時(shí)候初始化

首先,從這個(gè)問(wèn)題開(kāi)始我們今天的探索之旅,請(qǐng)看源碼

function Vue(){
    ... 其他處理
    initState(this)

    ...解析模板,生成DOM 插入頁(yè)面

}



function initState(vm) {


    ...處理 data,props,computed 等數(shù)據(jù)

    if (opts.watch) {
        initWatch(this, vm.$options.watch);
    }
}

沒(méi)錯(cuò),當(dāng)你調(diào)用 Vue 創(chuàng)建實(shí)例過(guò)程中,會(huì)去處理各種選項(xiàng),其中包括處理 watch

initWatch

處理 watch的方法是 initWatch,下面就呈上 源碼

function initWatch(vm, watch) {    

    for (var key in watch) {    

        var watchOpt = watch[key];
        createWatcher(vm, key, handler);
    }
}

然后這段源碼并沒(méi)有做什么驚天地泣鬼神的事情,只是簡(jiǎn)簡(jiǎn)單單的一個(gè)遍歷,然后每個(gè)watch 都使用一個(gè)叫什么 createWatcher 的東西去處理

這個(gè)函數(shù)到底是干嘛的?暗藏著什么秘密,歡迎來(lái)到我們今晚的 《走近科學(xué)》《源碼解析》

createWatcher 來(lái)看看他的真身

function createWatcher(
    // expOrFn 是 key,handler 可能是對(duì)象
    vm, expOrFn, handler,opts

) {    

    // 監(jiān)聽(tīng)屬性的值是一個(gè)對(duì)象,包含handler,deep,immediate

    if (typeof handler ==="object") {
        opts= handler
        handler = handler.handler
    }    



    // 回調(diào)函數(shù)是一個(gè)字符串,從 vm 獲取

    if (typeof handler === "string") {
        handler = vm[handler]
    }    



    // expOrFn 是 key,options 是watch 的全部選項(xiàng)

    vm.$watch(expOrFn, handler, opts)
}

大概就這樣吧

1、獲取到監(jiān)聽(tīng)回調(diào)

2、調(diào)用 vm.$watch

1、獲取監(jiān)聽(tīng)回調(diào)

首先,你傳入的 watch 配置可能是這三種(還有更多,差不多,不解釋?zhuān)鬯牢遥?/p>

如果配置是個(gè)對(duì)象,就取handler 字段

如果配置是函數(shù),那么直接就是 監(jiān)聽(tīng)回調(diào)

如果配置是字符串,從實(shí)例上獲取函數(shù)

2、調(diào)用 vm.$watch

看著這個(gè)方法,簡(jiǎn)直 mmp,還有完沒(méi)完,我從一個(gè)函數(shù)進(jìn)入一個(gè)函數(shù),又從這個(gè)函數(shù)進(jìn)入到另一個(gè)函數(shù),迷宮啊這是.....

顯然你不用急,下面還有更多......

好吧,還是先看源碼

Vue.prototype.$watch = function(
    // expOrFn 是 監(jiān)聽(tīng)的 key,cb 是監(jiān)聽(tīng)回調(diào),opts 是所有選項(xiàng)

    expOrFn, cb, opts

){    

    // expOrFn 是 監(jiān)聽(tīng)的 key,cb 是監(jiān)聽(tīng)的回調(diào),opts 是 監(jiān)聽(tīng)的所有選項(xiàng)

    var watcher = new Watcher(this, expOrFn, cb, opts);    



    // 設(shè)定了立即執(zhí)行,所以馬上執(zhí)行回調(diào)

    if (opts.immediate) {
        cb.call(this, watcher.value);
    }
};

看完了吧?這么短,你們肯定看得懂的啦,就兩件事

1、判斷是否立即執(zhí)行監(jiān)聽(tīng)回調(diào)

如果你設(shè)置了 immediate 的話,表示不用等我數(shù)據(jù)變化,初始化時(shí)馬上執(zhí)行一遍,執(zhí)行的代碼就是直接調(diào)用 回調(diào),綁定上下文,傳入監(jiān)聽(tīng)值

2、每個(gè) watch 配發(fā) watcher

代碼從這里開(kāi)始變得沉重,各位觀眾,喝口水,恰口飯,屏息觀看操作

看看 watcher 的源碼

“watcher 的源碼之前的文章也講過(guò)很多,但是對(duì)于每種選項(xiàng)的涉及的細(xì)節(jié)是不一樣的,所以每次都放上來(lái),但是只放跟本內(nèi)容相關(guān)的部分代碼,其他的省去以便我們快速理解”

var Watcher = function (vm, key, cb, opt) {  

    this.vm = vm;    

    this.deep = opt.deep;    

    this.cb = cb;  

    // 這里省略處理 xx.xx.xx 這種較復(fù)雜的key
    this.getter = function(obj) {        

        return obj[key]

    };    

    // this.get 作用就是執(zhí)行 this.getter函數(shù)

    this.value = this.get();
};

再看看,新建 watcher 的時(shí)候 ,傳入了什么

1、監(jiān)聽(tīng)的 key

2、監(jiān)聽(tīng)回調(diào) (Watch 中的cb)

3、監(jiān)聽(tīng)配置的options

這里會(huì)涉及到三個(gè)問(wèn)題,現(xiàn)在來(lái)解釋

1、怎么對(duì)設(shè)置的 key 進(jìn)行監(jiān)聽(tīng)?

我們要先對(duì) Watch 中的 this.getter 的函數(shù)進(jìn)行理解,他的本質(zhì)是為了獲取對(duì)象的key值

然后 getter 是在 watcher.get 中執(zhí)行的,看下 get 源碼

// 對(duì)本問(wèn)題進(jìn)行了獨(dú)家簡(jiǎn)單化的源碼

Watcher.prototype.get = function() {    

    var value = this.getter(this.vm);    

    return value

};

你能看到,Watch 在結(jié)尾會(huì)立即執(zhí)行一次 watcher.get,其中便會(huì)執(zhí)行 getter,便會(huì)根據(jù)你監(jiān)聽(tīng)的key,去實(shí)例上讀取并返回,存放在 watcher.value 上

看到了嗎,從實(shí)例上讀取屬性,這句話。

首先,watch 初始化之前,data 應(yīng)該初始化完畢了,每個(gè) data 數(shù)據(jù)都已經(jīng)是響應(yīng)式的

使用例子來(lái)說(shuō)明一下

當(dāng) watch.getter 執(zhí)行,而讀取了 vm.name 的時(shí)候,name的依賴(lài)收集器就會(huì)收集到 watch-watcher

于是 name 變化的時(shí)候,會(huì)可以通知到 watch,監(jiān)聽(tīng)就成功了

2、如何進(jìn)行深度監(jiān)聽(tīng)?

首先,深度監(jiān)聽(tīng),是你設(shè)置了 deep 的時(shí)候,如下

然后,觀察上面的 Watch 源碼,deep 會(huì)保存在watcher 中,以便后用

話鋒一轉(zhuǎn)

上一問(wèn)題說(shuō)過(guò),在 新建 watcher 的時(shí)候,會(huì)馬上執(zhí)行一個(gè) get,上個(gè)問(wèn)題的 get 源碼簡(jiǎn)化很多,把 處理深度監(jiān)聽(tīng)的部分去掉了,這里露出來(lái)了

Watcher.prototype.get = function() {
    Dep.target= this

    var value = this.getter(this.vm)    

    if (this.deep)  traverse(value)

    Dep.target= null
    return value
};

沒(méi)錯(cuò),處理深度監(jiān)聽(tīng)只有一條語(yǔ)句!

if (this.deep)  traverse(value)

value 是 getter 從實(shí)例上讀取監(jiān)聽(tīng)key 得到的值,沒(méi)有疑問(wèn)

但是 traverse 是何方神圣?come on 讓我們深入....

function traverse(val) {    

    var i, keys;    



    // 數(shù)組逐個(gè)遍歷

    if (Array.isArray(val)) {

        i = val.length;        

        // val[i] 就是讀取值了,然后值的對(duì)象就能收集到 watch-watcher

        while (i--) {
           traverse(val[i])
        }
    }    

    else {

        keys = Object.keys(val);
        i = keys.length;        

        // val[keys[i]] 就是讀取值了,然后值的對(duì)象就能收集到 watch-watcher

        while (i--) {
           traverse(val[keys[i]])
        }
    }
}

你看它這段代碼長(zhǎng),其實(shí)是個(gè)紙老虎,做的就是一個(gè)事情,不斷遞歸深入讀取對(duì)象

他的想法是這樣的

因?yàn)樽x取,就可以讓這個(gè)屬性收集到 watch-watcher 的原則

就算是深層級(jí)的對(duì)象,其中的每個(gè)屬性也都是響應(yīng)式的,每個(gè)屬性都有自己的依賴(lài)收集器

通過(guò)不斷深入的讀取每個(gè)屬性,這樣每個(gè)屬性就都可以收集到 watch-watcher 了

這樣不管對(duì)象內(nèi)多深的屬性變化,都會(huì)通知到 watch-watcher

于是這樣就完成了深度監(jiān)聽(tīng)

3、監(jiān)聽(tīng)值變化,如何觸發(fā)監(jiān)聽(tīng)函數(shù)?

通過(guò)上面的問(wèn)題,我們已經(jīng)了解了大部分了

監(jiān)聽(tīng)的數(shù)據(jù)變化的時(shí)候,就能通知 watch-watcher 更新,所謂通知更新,就是手動(dòng)調(diào)用 watch.update

速度看下 watcher.update 源碼

Watcher.prototype.update= function() {    

    var value = this.get();    

    if (this.deep) {        

        var oldValue = this.value;        

        this.value = value;        

        // cb 是監(jiān)聽(tīng)回調(diào)
        this.cb.call(this.vm, value, oldValue);
    }
};

很簡(jiǎn)單嘛,就是讀取一遍值,然后保存新值,接著 調(diào)用 監(jiān)聽(tīng)回調(diào),并傳入新值和 舊值

ok,就這樣

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/105380.html

相關(guān)文章

  • Vue原理Watch - 白話

    摘要:而是在初始化時(shí),在讀取了監(jiān)聽(tīng)的數(shù)據(jù)的值之后,便立即調(diào)用一遍你設(shè)置的監(jiān)聽(tīng)回調(diào),然后傳入剛讀取的值設(shè)置了時(shí),如何工作我們都知道有一個(gè)選項(xiàng),是用來(lái)深度監(jiān)聽(tīng)的。 寫(xiě)文章不容易,點(diǎn)個(gè)贊唄兄弟專(zhuān)注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺(jué)得排版難看,請(qǐng)點(diǎn)擊 下面鏈接 或者 拉到 下...

    hzx 評(píng)論0 收藏0
  • Vue原理】Mixins - 源碼

    寫(xiě)文章不容易,點(diǎn)個(gè)贊唄兄弟專(zhuān)注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺(jué)得排版難看,請(qǐng)點(diǎn)擊 下面鏈接 或者 拉到 下面關(guān)注公眾號(hào)也可以吧 【Vue原理】Mixins - 源碼版 今天探索的是 mixins 的源碼,mixins 根據(jù)不同的選項(xiàng)類(lèi)型會(huì)做不同的處理 篇幅會(huì)有些長(zhǎng),...

    gotham 評(píng)論0 收藏0
  • Vue原理】Mixin - 白話

    摘要:而我覺(jué)得現(xiàn)在出一個(gè)白話版,是讓大家有興趣去研究源碼的時(shí)候,可以提前理清一下思路。相當(dāng)于封裝,提取公共部分。顯然,今天我不是來(lái)教大家怎么用的,怎么用看文檔就好了,我是講解生命的真諦內(nèi)部的工作原理。而這個(gè)不會(huì)合并,直接替換掉整個(gè)選項(xiàng) 寫(xiě)文章不容易,點(diǎn)個(gè)贊唄兄弟專(zhuān)注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版...

    CollinPeng 評(píng)論0 收藏0
  • Vue原理】Props - 源碼

    寫(xiě)文章不容易,點(diǎn)個(gè)贊唄兄弟專(zhuān)注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺(jué)得排版難看,請(qǐng)點(diǎn)擊 下面鏈接 或者 拉到 下面關(guān)注公眾號(hào)也可以吧 【Vue原理】Props - 源碼版 今天記錄 Props 源碼流程,哎,這東西,就算是研究過(guò)了,也真是會(huì)隨著時(shí)間慢慢忘記的。 幸好我做...

    light 評(píng)論0 收藏0
  • Vue原理】NextTick - 源碼 之 服務(wù)Vue

    寫(xiě)文章不容易,點(diǎn)個(gè)贊唄兄弟專(zhuān)注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺(jué)得排版難看,請(qǐng)點(diǎn)擊 下面鏈接 或者 拉到 下面關(guān)注公眾號(hào)也可以吧 【Vue原理】NextTick - 源碼版 之 服務(wù)Vue 初次看的兄弟可以先看 【Vue原理】NextTick - 白話版 簡(jiǎn)單了解下...

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

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

0條評(píng)論

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