成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

VUE - MVVM - part6 - Array

0x584a / 1703人閱讀

摘要:回顧在前面的幾個(gè)中,我們實(shí)現(xiàn)對(duì)象的屬性的監(jiān)聽(tīng),但是有關(guān)于數(shù)組的行為我們一直沒(méi)有處理。并且上述的幾個(gè)數(shù)組方法是數(shù)組對(duì)象提供的,我們要想辦法去觸發(fā)下的函數(shù)。在設(shè)置值的時(shí)候就能成功觸發(fā)依賴。

看這篇之前,如果沒(méi)有看過(guò)之前的文章,可拉到文章末尾查看之前的文章。

回顧

在前面的幾個(gè) step 中,我們實(shí)現(xiàn)對(duì)象的屬性的監(jiān)聽(tīng),但是有關(guān)于數(shù)組的行為我們一直沒(méi)有處理。
我們先分析下導(dǎo)致數(shù)組有哪些行為:

調(diào)用方法:arr.splice(1, 2, "something1", "someting2")

直接賦值:arr[1] = "something"

解決行為一

首先我們知道數(shù)組下的一些方法是會(huì)對(duì)原數(shù)組照成影響的,有以下幾個(gè):

push

pop

shift

unshift

splice

sort

reverse

這幾個(gè)方法總的來(lái)說(shuō)會(huì)照成幾個(gè)影響:

數(shù)組長(zhǎng)度發(fā)生變化

數(shù)組內(nèi)元素順序發(fā)生變化

不像對(duì)象,如果對(duì)象的 key 值的順序發(fā)生變化,是不會(huì)影響視圖的變化,但數(shù)組的順序如果發(fā)生變化,視圖是要變化的。

也就是說(shuō)當(dāng)著幾個(gè)方法觸發(fā)的時(shí)候,我們需要視圖的更新,也就是要觸發(fā) Dep 中的 notify 函數(shù)。

但是縱觀我們現(xiàn)在實(shí)現(xiàn)的代碼( step5 中的代碼),我們并沒(méi)有特地的為數(shù)組提供一個(gè) Dep。

并且上述的幾個(gè)數(shù)組方法是數(shù)組對(duì)象提供的,我們要想辦法去觸發(fā) Dep 下的 notify 函數(shù)。

我們先為數(shù)組提供一個(gè) Dep ,完善后的 Observer

export class Observer {

    constructor(value) {
        this.value = value
        if (Array.isArray(value)) {
            // 為數(shù)組設(shè)置一個(gè)特殊的 Dep
            this.dep = new Dep()
            this.observeArray(value)
        } else {
            this.walk(value)
        }
        Object.defineProperty(value, "__ob__", {
            value: this,
            enumerable: false,
            writable: true,
            configurable: true
        })
    }

    /**
     * 遍歷對(duì)象下屬性,使得屬性變成可監(jiān)聽(tīng)的結(jié)構(gòu)
     */
    walk(obj) {
        const keys = Object.keys(obj)
        for (let i = 0; i < keys.length; i++) {
            defineReactive(obj, keys[i], obj[keys[i]])
        }
    }

    /**
     * 同上,遍歷數(shù)組
     */
    observeArray (items) {
        for (let i = 0, l = items.length; i < l; i++) {
            observe(items[i])
        }
    }

}

同樣的在 defineReactive 我們需要處理數(shù)組添加依賴的邏輯

export function defineReactive(object, key, value) {
    let dep = new Dep()
    let childOb = observe(value)
    Object.defineProperty(object, key, {
        configurable: true,
        enumerable: true,
        get: function () {
            if (Dep.target) {
                dep.addSub(Dep.target)
                Dep.target.addDep(dep)
                // 處理數(shù)組的依賴
                if(Array.isArray(value)){
                    childOb.dep.addSub(Dep.target)
                    Dep.target.addDep(childOb.dep)
                }
            }
            return value
        },
        set: function (newValue) {
            if (newValue !== value) {
                value = newValue
                dep.notify()
            }
        }
    })
}

ok 我們現(xiàn)在完成了依賴的添加,剩下的我們要實(shí)現(xiàn)依賴的觸發(fā)。

處理方法:在數(shù)組對(duì)象調(diào)用特定方法時(shí),首先找到的應(yīng)該是我們自己寫(xiě)的方法,而這個(gè)方法中調(diào)用了原始方法,并觸發(fā)依賴。

我們先來(lái)包裝一下方法,得到一些同名方法:

const arrayProto = Array.prototype
// 復(fù)制方法
export const arrayMethods = Object.create(arrayProto)

const methodsToPatch = [
    "push",
    "pop",
    "shift",
    "unshift",
    "splice",
    "sort",
    "reverse"
]

/**
 * 改變數(shù)組的默認(rèn)處理,將新添加的對(duì)象添加監(jiān)聽(tīng)
 */
methodsToPatch.forEach(function (method) {
    // 原始的數(shù)組處理方法
    const original = arrayProto[method]
    let mutator = function (...args) {
        const result = original.apply(this, args)
        const ob = this.__ob__
        let inserted
        switch (method) {
            case "push":
            case "unshift":
                inserted = args
                break
            case "splice":
                inserted = args.slice(2)
                break
        }
        // 新添加的對(duì)象需要添加監(jiān)聽(tīng)
        if (inserted) ob.observeArray(inserted)
        // 觸發(fā) notify 方法
        ob.dep.notify()
        return result
    }
    Object.defineProperty(arrayMethods, method, {
        value: mutator,
        enumerable: false,
        writable: true,
        configurable: true
    })
})

ok 我們現(xiàn)在得到了一些列同名的方法,我只要確保在調(diào)用時(shí),先調(diào)用到我們的方法即可。

有兩種方式可以實(shí)現(xiàn):

數(shù)組對(duì)象上直接有該方法,這樣就不會(huì)去找對(duì)象上的原型鏈

覆蓋對(duì)象的 __proto__ ,這樣尋找原型鏈時(shí),就會(huì)先找到我們的方法

具體到代碼中的實(shí)現(xiàn):

export class Observer {

    constructor(value) {
        this.value = value
        if (Array.isArray(value)) {
            this.dep = new Dep()
            const augment = ("__proto__" in {})
                ? protoAugment
                : copyAugment
            // 覆蓋數(shù)組中一些改變了原數(shù)組的方法,使得方法得以監(jiān)聽(tīng)
            augment(value, arrayMethods, arrayKeys)
            this.observeArray(value)
        } else {
            this.walk(value)
        }
        ...
    }
    ...
}

/**
 * 如果能使用 __proto__ 則將數(shù)組的處理方法進(jìn)行替換
 */
function protoAugment (target, src, keys) {
    target.__proto__ = src
}

/**
 * 如果不能使用 __proto__ 則直接將該方法定義在當(dāng)前對(duì)象下
 */
function copyAugment (target, src, keys) {
    for (let i = 0, l = keys.length; i < l; i++) {
        const key = keys[i]
        Object.defineProperty(target, key, {
            value: src[key],
            enumerable: false,
            writable: true,
            configurable: true
        })
    }
}

測(cè)試一下:

let object = {
    arrayTest: [1, 2, 3, 4, 5]
}

observe(object)

let watcher = new Watcher(object, function () {
    return this.arrayTest.reduce((sum, num) => sum + num)
}, function (newValue, oldValue) {
    console.log(`監(jiān)聽(tīng)函數(shù),數(shù)組內(nèi)所有元素 = ${newValue}`)
})

object.arrayTest.push(10)
// 監(jiān)聽(tīng)函數(shù),數(shù)組內(nèi)所有元素 = 25

到現(xiàn)在為止,我們成功的在數(shù)組調(diào)用方法的時(shí)候,添加并觸發(fā)了依賴。

解決行為二

首先先說(shuō)明,數(shù)組下的索引是和對(duì)象下的鍵有同樣的表現(xiàn),也就是可以用 defineReactive 來(lái)處理索引值,但是數(shù)組是用來(lái)存放一系列的值,我們并不能一開(kāi)始就確定數(shù)組的長(zhǎng)度,并且極有可能剛開(kāi)始數(shù)組長(zhǎng)度為 0,之后數(shù)組中的索引對(duì)應(yīng)的內(nèi)容也會(huì)不斷的變化,所以為索引調(diào)用 defineReactive 是不切實(shí)際的。

但是類(lèi)似于 arr[1] = "something" 這樣的賦值在數(shù)組中也是常見(jiàn)的操作,在 Vue 中實(shí)現(xiàn)了 $set 具體的細(xì)節(jié)這里不談,這里實(shí)現(xiàn)了另一種方法,我們僅僅需要在數(shù)組對(duì)象下添加一個(gè)方法即可:

arrayMethods.$apply = function () {
    this.__ob__.observeArray(this)
    this.__ob__.dep.notify()
}

測(cè)試一下:

object.arrayTest[1] = 10
object.arrayTest.$apply()
// 監(jiān)聽(tīng)函數(shù),數(shù)組內(nèi)所有元素 = 33

到目前為了,一個(gè)完整的數(shù)據(jù)監(jiān)聽(tīng)的模型也就完成了,我們可以使用 observe 方法來(lái)得到一個(gè)可監(jiān)聽(tīng)結(jié)構(gòu),然后用 Watcher 添加依賴。

在設(shè)置值的時(shí)候就能成功觸發(fā)依賴。

點(diǎn)擊查看相關(guān)代碼

系列文章地址

VUE - MVVM - part1 - defineProperty

VUE - MVVM - part2 - Dep

VUE - MVVM - part3 - Watcher

VUE - MVVM - part4 - 優(yōu)化Watcher

VUE - MVVM - part5 - Observe

VUE - MVVM - part6 - Array

VUE - MVVM - part7 - Event

VUE - MVVM - part8 - 優(yōu)化Event

VUE - MVVM - part9 - Vue

VUE - MVVM - part10 - Computed

VUE - MVVM - part11 - Extend

VUE - MVVM - part12 - props

VUE - MVVM - part13 - inject & 總結(jié)

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/94449.html

相關(guān)文章

  • VUE - MVVM - part1 - defineProperty

    摘要:在中關(guān)于如何實(shí)現(xiàn)在網(wǎng)上可以搜出不少,在看了部分源碼后,梳理一下內(nèi)容。換個(gè)說(shuō)法,當(dāng)我們?nèi)≈档臅r(shí)候,函數(shù)自動(dòng)幫我們添加了針對(duì)當(dāng)前值的依賴,當(dāng)這個(gè)值發(fā)生變化的時(shí)候,處理了這些依賴,比如說(shuō)節(jié)點(diǎn)的變化。 在 VUE 中關(guān)于如何實(shí)現(xiàn)在網(wǎng)上可以搜出不少,在看了部分源碼后,梳理一下內(nèi)容。 首先,我們需要了解一下 js 中的一個(gè) API :Object.defineProperty(obj, prop,...

    liukai90 評(píng)論0 收藏0
  • VUE - MVVM - part7 - Event

    摘要:事件是什么在標(biāo)準(zhǔn)瀏覽器中,我們經(jīng)常使用來(lái)為一個(gè)添加一個(gè)事件等。仔細(xì)看這些情況,歸結(jié)到代碼中,無(wú)非就是一個(gè)行為或情況的名稱,和一些列的動(dòng)作,而在中動(dòng)作就是,一系列的動(dòng)作就是一個(gè)函數(shù)的集合。 看這篇之前,如果沒(méi)有看過(guò)之前的文章,可拉到文章末尾查看之前的文章。 事件是什么? 在標(biāo)準(zhǔn)瀏覽器中,我們經(jīng)常使用:addEventListener 來(lái)為一個(gè) DOM 添加一個(gè)事件(click、mouse...

    xialong 評(píng)論0 收藏0
  • VUE - MVVM - part2 - Dep

    摘要:看這篇之前,如果沒(méi)看過(guò)先移步看實(shí)現(xiàn)中。同樣的,在取值時(shí)收集依賴,在設(shè)置值當(dāng)值發(fā)生變化時(shí)觸發(fā)依賴。中實(shí)現(xiàn)了一個(gè)的類(lèi)來(lái)處理以上兩個(gè)問(wèn)題,之后再說(shuō)。以下語(yǔ)法下的,源碼中差不多就這樣點(diǎn)擊查看相關(guān)代碼系列文章地址優(yōu)化優(yōu)化總結(jié) 看這篇之前,如果沒(méi)看過(guò) step1 先移步看 實(shí)現(xiàn) VUE 中 MVVM - step1 - defineProperty。 在上一篇我們大概實(shí)現(xiàn)了,Vue 中的依賴收集和...

    hover_lew 評(píng)論0 收藏0
  • VUE - MVVM - part11 - Extend

    摘要:所以方法,是對(duì)默認(rèn)進(jìn)行擴(kuò)展,從而實(shí)現(xiàn)擴(kuò)展。這里我用了這個(gè)庫(kù)提供的合并方法,用來(lái)合并兩個(gè)對(duì)象,并不會(huì)修改原對(duì)象的內(nèi)容。測(cè)試符合我們的預(yù)期,方法也就實(shí)現(xiàn)了,下一步,實(shí)現(xiàn)父子組件。系列文章地址優(yōu)化優(yōu)化總結(jié) 看這篇之前,如果沒(méi)有看過(guò)之前的文章,移步拉到文章末尾查看之前的文章。 組件的擴(kuò)展 在 Vue 中有 extend 方法可以擴(kuò)展 Vue 的實(shí)例,在上一步中,有一些實(shí)現(xiàn)是必須要通過(guò)子父組件才...

    cartoon 評(píng)論0 收藏0
  • VUE - MVVM - part8 - 優(yōu)化Event

    摘要:看這篇之前,如果沒(méi)有看過(guò)之前的文章,可拉到文章末尾查看之前的文章?;仡櫾谏弦徊轿覀儗?shí)現(xiàn)了一個(gè)簡(jiǎn)易的事件管理的類(lèi),接下來(lái)我們把它給優(yōu)化下,方便我們的使用。接著我們來(lái)優(yōu)化。 看這篇之前,如果沒(méi)有看過(guò)之前的文章,可拉到文章末尾查看之前的文章。 回顧 在上一步我們實(shí)現(xiàn)了一個(gè)簡(jiǎn)易的事件管理的類(lèi),接下來(lái)我們把它給優(yōu)化下,方便我們的使用。主要優(yōu)化內(nèi)容: 方便為多個(gè)事件添加同一個(gè)函數(shù) 方便為一個(gè)事件...

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

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

0條評(píng)論

閱讀需要支付1元查看
<