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

資訊專欄INFORMATION COLUMN

Vue偵測相關(guān)api

zhangfaliang / 2789人閱讀

vm.$watch

用法: vm.$watch( expOrFn, callback, [options] ),返回值為unwatch是一個函數(shù)用來取消觀察;下面主要理解options中的兩個參數(shù)deepimmediate以及unwatch

Vue.prototype.$watch = function (expOrFn, cb, options) {
    const vm = this
    options = options || {}
    const watcher = new Watcher(vm, expOrFn, cb, options)  
    if(options.immediate) {
        cb.call(vm, watcher,.value)
    }
    return function unwatchFn() {
        watcher.teardown()
    }
}
immediate

從上面代碼中可以看出當(dāng)immediatetrue時,就會直接進(jìn)行執(zhí)行回調(diào)函數(shù)

unwatch 實現(xiàn)方式是:

將被訪問到的數(shù)據(jù)dep收集到watchs實例對象上,通過this.deps存起來

將被訪問到的數(shù)據(jù)dep.id收集到watchs實例對象上,通過this.depIds存起來

最后通過watchs實例對象的teardown進(jìn)行刪除

class Watcher {
    constructor (vm, expOrFn, cb) {
        this.vm = vm
        this.deps = []
        this.depIds = new Set()
        if(typeof expOrFn === "function") {
            this.getter = expOrFn
        }else {
            this.getter = parsePath(expOrFn)
        }
        this.cb = cb
        this.value = this.get()
    }
    ....
    addDep (dep) {
        const id = dep.id             //參數(shù)dep是Dep實例對象
        if(!this.depIds.has(id)) {    //判斷是否存在避免重復(fù)添加
            this.depIds.add(id)       
            this.deps.push(dep)
            dep.addSub(this)         //this 是依賴
        }
    }
    teardown () {
        let i = this.deps.length
        while (i--) {
            this.deps[i].removeSub(this)
        }
    }
}
let uid = 0
class Dep {
    constructor () {
        this.id = uid++
        ...
    }
    ...
    depend () {
        if(window.target) {
            window.target.addDep(this)    //將this即當(dāng)前dep對象加入到watcher對象上
        }
    }
    removeSub (sub) {
        const index = this.subs.indexOf(sub)
        if(index > -1) {
            return this.subs.splice(index, 1)
        }
    }
}
分析

當(dāng)執(zhí)行teardown() 時需要循環(huán);因為例如expOrFn = function () { return this.name + this.age },這時會有兩個dep分別是nameage分別都加入了watcher依賴(this),都會加入到this.deps中,所以需要循環(huán)將含有依賴的dep都刪除其依賴

deep 需要明白的是

deep干啥用的,例如data = {arr: [1, 2, {b: 6]},當(dāng)我們只是監(jiān)聽data.arr時,在[1, 2, {b: 66}]這個數(shù)值內(nèi)部發(fā)生變化時,也需要觸發(fā),即b = 888

怎么做呢?
class Watcher {
    constructor (vm, expOrFn, cb, options) {
        this.vm = vm
        this.deps = []
        this.depIds = new Set()
        if(typeof expOrFn === "function") {
            this.getter = expOrFn
        }else {
            this.getter = parsePath(expOrFn)
        }
        if(options) {                    //取值
            this.deep = !!options.deep
        }else {
            this.deep = false
        }
        this.cb = cb
        this.value = this.get()
    }
    get () {
        window.target = this
        let value = this.getter.call(vm, vm)
        if(this.deep) {
            traverse(value)
        }
        window.target = undefined
        return value
    }
    ...
}
const seenObjects = new Set()
function traverse (val) {
    _traverse(val, seenObjects)
    seenObjects.clear()
}
function _traverse(val, seen) {
    let i, keys
    const isA = Array.isArray(val)
    if((!isA && isObject(val)) || Object.isFrozen(val)) {  //判斷val是否是對象或者數(shù)組以及是否被凍結(jié)
        return
    }
    if(val._ob_) {
        const depId = val._ob_.dep.id     //可以看前面一篇我們對Observer類添加了this.dep = new Dep(),所以能訪問其dep.id
        if(seen.has(depId)) {
            return
        }
        seen.add(depId)
    }
    if(isA) {
        i = val.length
        while (i--) _traverse(val[i], seen)
    } else {
        keys = Object.keys(val)
        i = keys.length
        while (i--) _traverse(val[i], seen)
    }
}
分析

window.target = this,寄存依賴

let value = this.getter.call(vm, vm) 訪問當(dāng)前val,并執(zhí)行get

dep.depend(),如果發(fā)現(xiàn)val為數(shù)組,則將依賴加入到observerdep中,也就實現(xiàn)了對當(dāng)前數(shù)組的攔截

traverse(value) 也就是執(zhí)行_traverse(val, seenObjects);核心就是對被Observerval通過val[i]通過這種操作,間接觸發(fā)get,將依賴添加到當(dāng)前數(shù)值的dep中,這樣也就實現(xiàn)了,當(dāng)內(nèi)部數(shù)據(jù)發(fā)生變化,也會循環(huán)subs執(zhí)行依賴的update,從而觸發(fā)回調(diào);當(dāng)是數(shù)組時,只需進(jìn)行遍歷,看內(nèi)部是否有Object對象即可,因為在第二步的時候,會對val進(jìn)行判斷是否是數(shù)組,變改變七個方法的value,在遍歷;所以這邊只要是內(nèi)部數(shù)組都會進(jìn)行攔截操作,添加依賴,即對象{}這種沒沒添加依賴。

seenObjects.clear()當(dāng)內(nèi)部所以類型數(shù)據(jù)都添加好其依賴后,就清空。

window.target = undefined消除依賴

vm.$set

用法: vm.$set(target, key, value)

作用

對于數(shù)組,進(jìn)行set則是添加新元素,并需要觸發(fā)依賴更新

對于對象,如果key值存在,則是修改value;不存在,則是添加新元素,需新元素要進(jìn)行響應(yīng)式處理,以及觸發(fā)更新

對于對象本身不是響應(yīng)式,則直接添加key-value,無需處理

Vue.prototype.$set = function (target, key, val) {
   if(Array.isArray(target) && isValidArrayIndex(key)) {    //是數(shù)組并且key有效
        target.length = Math.max(target.length, key)   //處理key > target.length
        target.splice(key, 1, val)   //添加新元素,并輸出依賴更新同時新元素也會進(jìn)行`Obsever`處理
        return val
   }
   if(key in targert && !(key in Object.prototype) {  //能遍歷并且是自身key
        target[key] = val   //觸發(fā)set,執(zhí)行依賴更新
        return val
   }
   const ob = target._ob_
   if(target.isVue || (ob && ob.vm.Count) {  //不是vue實例也不是vue實例的根對象(即不是this.$data跟對象)
       //觸發(fā)警告
       return
   }
   if(!ob) {    //只添加
       target[key] = val
       return val
   }
   defineReactive(ob.value, key, val)  //進(jìn)行響應(yīng)式處理
   ob.dep.notify()  //觸發(fā)依賴更新
   returnv val
}
vm.$delete

用法: vm.$delete( target, key)

作用

對于數(shù)組,進(jìn)行delete則是刪除新元素,并需要觸發(fā)依賴更新

對于對象,如果key值不存在,直接return,存在,刪除元素,

對于對象本身不是響應(yīng)式,則只刪除key-value,無需其他處理

Vue.prototype.$delete = function (target, key) {
    if(Array.isArray(target) && isValidArrayIndex(key)) {
        target.splice(key, 1)
        return
    }
    const ob = target._ob_
    if(target.isVue || (ob && ob.vm.Count) {  //不是vue實例也不是vue實例的根對象(即不是this.$data跟對象)
        //觸發(fā)警告
        return
   }
   if(!hasOwn(target, key)) {
       return
   }
    delete target[key]
    if(!ob) {
        return
    }
    ob.dep.notify()
}

掘金地址

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

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

相關(guān)文章

  • vue的變化偵測

    摘要:由來最近在看深入淺出,第一篇變化偵測,想把自己的理解總結(jié)一下。的變化偵測總結(jié)一下我看了后的理解將數(shù)據(jù)變成可響應(yīng)式的,即將數(shù)據(jù)變成可監(jiān)聽的。由來 最近在看深入淺出vuejs,第一篇變化偵測,想把自己的理解總結(jié)一下。 Object的變化偵測 總結(jié)一下我看了后的理解 將數(shù)據(jù)變成可響應(yīng)式的,即將數(shù)據(jù)變成可監(jiān)聽的。通過Observer類來實現(xiàn) 依賴是什么?就是這個數(shù)據(jù)在哪里用到了,相當(dāng)于this當(dāng)...

    zhoutk 評論0 收藏0
  • vue的變化偵測

    摘要:由來最近在看深入淺出,第一篇變化偵測,想把自己的理解總結(jié)一下。的變化偵測總結(jié)一下我看了后的理解將數(shù)據(jù)變成可響應(yīng)式的,即將數(shù)據(jù)變成可監(jiān)聽的。 由來 最近在看深入淺出vuejs,第一篇變化偵測,想把自己的理解總結(jié)一下。 Object的變化偵測 總結(jié)一下我看了后的理解 將數(shù)據(jù)變成可響應(yīng)式的,即將數(shù)據(jù)變成可監(jiān)聽的。通過Observer類來實現(xiàn) 依賴是什么?就是這個數(shù)據(jù)在哪里用到了,相當(dāng)于th...

    Freeman 評論0 收藏0
  • 深入淺出Vue響應(yīng)式原理

    摘要:總結(jié)最后我們依照下圖參考深入淺出,再來回顧下整個過程在后,會調(diào)用函數(shù)進(jìn)行初始化,也就是過程,在這個過程通過轉(zhuǎn)換成了的形式,來對數(shù)據(jù)追蹤變化,當(dāng)被設(shè)置的對象被讀取的時候會執(zhí)行函數(shù),而在當(dāng)被賦值的時候會執(zhí)行函數(shù)。 前言 Vue 最獨特的特性之一,是其非侵入性的響應(yīng)式系統(tǒng)。數(shù)據(jù)模型僅僅是普通的 JavaScript 對象。而當(dāng)你修改它們時,視圖會進(jìn)行更新。這使得狀態(tài)管理非常簡單直接,不過理解...

    yiliang 評論0 收藏0
  • Zepto 源碼分析 2 - Polyfill 設(shè)計

    摘要:此模塊包含的設(shè)計思路即為預(yù)以匹配降級方案。沒有默認(rèn)編譯該模塊,以及利用該模塊判斷后提供平臺相關(guān)邏輯的主要原因在于其設(shè)計原則的代碼完成核心的功能。此處,也引出了代碼實現(xiàn)的另一個基本原則面向功能標(biāo)準(zhǔn),先功能覆蓋再優(yōu)雅降級。 在進(jìn)入 Zepto Core 模塊代碼之前,本節(jié)簡略列舉 Zepto 及其他開源庫中一些 Polyfill 的設(shè)計思路與實現(xiàn)技巧。 涉及模塊:IE/IOS 3/Dete...

    chuyao 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<