最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue2響應(yīng)式系統(tǒng)介紹

 更新時(shí)間:2022年04月12日 20:38:53   作者:windliang  
這篇文章主要介紹了Vue2響應(yīng)式系統(tǒng),響應(yīng)式系統(tǒng)主要實(shí)現(xiàn)某個(gè)依賴了數(shù)據(jù)的函數(shù),當(dāng)所依賴的數(shù)據(jù)改變的時(shí)候,該函數(shù)要重新執(zhí)行,下文更多相關(guān)介紹需要的小伙伴可以參考一下

前言:

目前工作中大概有 的需求是在用 的技術(shù)棧,所謂知其然更要知其所以然,為了更好的使用 、更快的排查問(wèn)題,最近學(xué)習(xí)了源碼相關(guān)的一些知識(shí),雖然網(wǎng)上總結(jié) 的很多很多了,不少自己一個(gè),但也不多自己一個(gè),歡迎一起討論學(xué)習(xí),發(fā)現(xiàn)問(wèn)題歡迎指出。40%Vue2VueVue

一、響應(yīng)式系統(tǒng)要干什么

回到最簡(jiǎn)單的代碼:

data = {
    text: 'hello, world'
}

const updateComponent = () => {
    console.log('收到', data.text);
}

updateComponent()

data.text = 'hello, liang'
// 運(yùn)行結(jié)果
// 收到 hello, world

響應(yīng)式系統(tǒng)要做的事情:某個(gè)依賴了 數(shù)據(jù)的函數(shù),當(dāng)所依賴的 數(shù)據(jù)改變的時(shí)候,該函數(shù)要重新執(zhí)行。datadata

我們期望的效果:當(dāng)上邊 修改的時(shí)候, 函數(shù)再執(zhí)行一次。data.textupdateComponent

為了實(shí)現(xiàn)響應(yīng)式系統(tǒng),我們需要做兩件事情:

  • 知道 中的數(shù)據(jù)被哪些函數(shù)依賴data
  • data中的數(shù)據(jù)改變的時(shí)候去調(diào)用依賴它的函數(shù)們

為了實(shí)現(xiàn)第 點(diǎn),我們需要在執(zhí)行函數(shù)的時(shí)候,將當(dāng)前函數(shù)保存起來(lái),然后在讀取數(shù)據(jù)的時(shí)候?qū)⒃摵瘮?shù)保存到當(dāng)前數(shù)據(jù)中。1

第 點(diǎn)就迎刃而解了,當(dāng)修改數(shù)據(jù)的時(shí)候?qū)⒈4嫫饋?lái)的函數(shù)執(zhí)行一次即可。2

讀取數(shù)據(jù)修改數(shù)據(jù)的時(shí)候需要做額外的事情,我們可以通過(guò) 重寫對(duì)象屬性的 和 函數(shù)。Object.defineProperty()getset

二、響應(yīng)式數(shù)據(jù)

我們來(lái)寫一個(gè)函數(shù),重寫屬性的 和 函數(shù)。getset

/**
 * Define a reactive property on an Object.
 */
export function defineReactive(obj, key, val) {
    const property = Object.getOwnPropertyDescriptor(obj, key);
    // 讀取用戶可能自己定義了的 get、set
    const getter = property && property.get;
    const setter = property && property.set;
    // val 沒(méi)有傳進(jìn)來(lái)話進(jìn)行手動(dòng)賦值
    if ((!getter || setter) && arguments.length === 2) {
        val = obj[key];
    }

    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: function reactiveGetter() {
            const value = getter ? getter.call(obj) : val;
            /*********************************************/
            // 1.這里需要去保存當(dāng)前在執(zhí)行的函數(shù)
            /*********************************************/
            return value;
        },
        set: function reactiveSetter(newVal) {
            const value = getter ? getter.call(obj) : val;

            if (setter) {
                setter.call(obj, newVal);
            } else {
                val = newVal;
            }
            /*********************************************/
            // 2.將依賴當(dāng)前數(shù)據(jù)依賴的函數(shù)執(zhí)行
            /*********************************************/
        },
    });
}

為了調(diào)用更方便,我們把第 步和第 步的操作封裝一個(gè) 類。12Dep

export default class Dep {
    static target; //當(dāng)前在執(zhí)行的函數(shù)
    subs; // 依賴的函數(shù)
    constructor() {
        this.subs = []; // 保存所有需要執(zhí)行的函數(shù)
    }

    addSub(sub) {
        this.subs.push(sub);
    }

    depend() {
        // 觸發(fā) get 的時(shí)候走到這里
        if (Dep.target) {
            // 委托給 Dep.target 去調(diào)用 addSub
            Dep.target.addDep(this);
        }
    }

    notify() {
        for (let i = 0, l = this.subs.length; i < l; i++) {
            this.subs[i].update();
        }
    }
}

Dep.target = null; // 靜態(tài)變量,全局唯一

我們將當(dāng)前執(zhí)行的函數(shù)保存到 類的 變量上。Deptarget

三、保存當(dāng)前正在執(zhí)行的函數(shù)

為了保存當(dāng)前的函數(shù),我們還需要寫一個(gè) 類,將需要執(zhí)行的函數(shù)傳入,保存到 類中的 屬性中,然后交由 類負(fù)責(zé)執(zhí)行。WatcherWatchergetterWatcher

這樣在 類中, 中保存的就不是當(dāng)前函數(shù)了,而是持有當(dāng)前函數(shù)的 對(duì)象。DepsubsWatcher

import Dep from "./dep";
export default class Watcher {
    constructor(Fn) {
        this.getter = Fn;
        this.get();
    }

    /**
     * Evaluate the getter, and re-collect dependencies.
     */
    get() {
        Dep.target = this; // 保存包裝了當(dāng)前正在執(zhí)行的函數(shù)的 Watcher
        let value;
        try {
          	// 調(diào)用當(dāng)前傳進(jìn)來(lái)的函數(shù),觸發(fā)對(duì)象屬性的 get
            value = this.getter.call();
        } catch (e) {
            throw e;
        }
        return value;
    }

    /**
     * Add a dependency to this directive.
     */
    addDep(dep) {
      	// 觸發(fā) get 后會(huì)走到這里,收集當(dāng)前依賴
        // 當(dāng)前正在執(zhí)行的函數(shù)的 Watcher 保存到 dep 中的 subs 中
        dep.addSub(this);
    }

    /**
     * Subscriber interface.
     * Will be called when a dependency changes.
     */
  	// 修改對(duì)象屬性值的時(shí)候觸發(fā) set,走到這里
    update() {
        this.run();
    }

    /**
     * Scheduler job interface.
     * Will be called by the scheduler.
     */
    run() {
        this.get();
    }
}

Watcher 的作用就是將正在執(zhí)行的函數(shù)通過(guò) 包裝后保存到 中,然后調(diào)用傳進(jìn)來(lái)的函數(shù),此時(shí)觸發(fā)對(duì)象屬性的 函數(shù),會(huì)收集當(dāng)前 。WatcherDep.targetgetWatcher

如果未來(lái)修改對(duì)象屬性的值,會(huì)觸發(fā)對(duì)象屬性的 ,接著就會(huì)調(diào)用之前收集到的 對(duì)象,通過(guò) 對(duì)象的 方法,來(lái)調(diào)用最初執(zhí)行的函數(shù)。setWatcherWatcheruptate

四、響應(yīng)式數(shù)據(jù)

回到我們之前沒(méi)寫完的 函數(shù),按照上邊的思路,我們來(lái)補(bǔ)全一下。defineReactive

import Dep from "./dep";
/**
 * Define a reactive property on an Object.
 */
export function defineReactive(obj, key, val) {
    const property = Object.getOwnPropertyDescriptor(obj, key);
    // 讀取用戶可能自己定義了的 get、set
    const getter = property && property.get;
    const setter = property && property.set;
    // val 沒(méi)有傳進(jìn)來(lái)話進(jìn)行手動(dòng)賦值
    if ((!getter || setter) && arguments.length === 2) {
        val = obj[key];
    }

    /*********************************************/
    const dep = new Dep(); // 持有一個(gè) Dep 對(duì)象,用來(lái)保存所有依賴于該變量的 Watcher
    /*********************************************/

    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: function reactiveGetter() {
            const value = getter ? getter.call(obj) : val;
            /*********************************************/
            // 1.這里需要去保存當(dāng)前在執(zhí)行的函數(shù)
            if (Dep.target) {
                dep.depend();
            }
            /*********************************************/
            return value;
        },
        set: function reactiveSetter(newVal) {
            const value = getter ? getter.call(obj) : val;

            if (setter) {
                setter.call(obj, newVal);
            } else {
                val = newVal;
            }
            /*********************************************/
            // 2.將依賴當(dāng)前數(shù)據(jù)依賴的函數(shù)執(zhí)行
            dep.notify();
            /*********************************************/
        },
    });
}

五、Observer 對(duì)象

我們?cè)賹懸粋€(gè) 方法,把對(duì)象的全部屬性都變成響應(yīng)式的。Observer

export class Observer {
    constructor(value) {
        this.walk(value);
    }

    /**
     * 遍歷對(duì)象所有的屬性,調(diào)用 defineReactive
     * 攔截對(duì)象屬性的 get 和 set 方法
     */
    walk(obj) {
        const keys = Object.keys(obj);
        for (let i = 0; i < keys.length; i++) {
            defineReactive(obj, keys[i]);
        }
    }
}

我們提供一個(gè) 方法來(lái)負(fù)責(zé)創(chuàng)建 對(duì)象。observeObserver

export function observe(value) {
    let ob = new Observer(value);
    return ob;
}

六、測(cè)試

將上邊的方法引入到文章最開(kāi)頭的例子,來(lái)執(zhí)行一下:

import { observe } from "./reactive";
import Watcher from "./watcher";
const data = {
    text: "hello, world",
};
// 將數(shù)據(jù)變成響應(yīng)式的
observe(data);

const updateComponent = () => {
    console.log("收到", data.text);
};

// 當(dāng)前函數(shù)由 Watcher 進(jìn)行執(zhí)行
new Watcher(updateComponent);

data.text = "hello, liang";

此時(shí)就會(huì)輸出兩次了~

收到 hello, world
收到 hello, liang

說(shuō)明我們的響應(yīng)式系統(tǒng)成功了。

七、總結(jié)

image-20220329092722630

先從整體理解了響應(yīng)式系統(tǒng)的整個(gè)流程:

每個(gè)屬性有一個(gè) 數(shù)組, 會(huì)持有當(dāng)前執(zhí)行的函數(shù),當(dāng)讀取屬性的時(shí)候觸發(fā) ,將當(dāng)前 保存到 數(shù)組中,當(dāng)屬性值修改的時(shí)候,再通過(guò) 數(shù)組中的 對(duì)象執(zhí)行之前保存的函數(shù)。subsWatchergetWatchersubssubsWatcher

到此這篇關(guān)于Vue2響應(yīng)式系統(tǒng)介紹的文章就介紹到這了,更多相關(guān)Vue2響應(yīng)式系統(tǒng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue?如何配置eslint代碼檢查

    vue?如何配置eslint代碼檢查

    這篇文章主要介紹了vue?如何配置eslint代碼檢查,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • Vue引入echarts方法與使用介紹

    Vue引入echarts方法與使用介紹

    Echarts,它是一個(gè)與框架無(wú)關(guān)的?JS?圖表庫(kù),但是它基于Js,這樣很多框架都能使用它,例如Vue,估計(jì)IONIC也能用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • vuex中store存儲(chǔ)store.commit和store.dispatch的區(qū)別及說(shuō)明

    vuex中store存儲(chǔ)store.commit和store.dispatch的區(qū)別及說(shuō)明

    這篇文章主要介紹了vuex中store存儲(chǔ)store.commit和store.dispatch的區(qū)別及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • 實(shí)現(xiàn)elementUI表單的全局驗(yàn)證的方法步驟

    實(shí)現(xiàn)elementUI表單的全局驗(yàn)證的方法步驟

    這篇文章主要介紹了實(shí)現(xiàn)elementUI表單的全局驗(yàn)證的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • vue和iview實(shí)現(xiàn)Scroll 數(shù)據(jù)無(wú)限滾動(dòng)功能

    vue和iview實(shí)現(xiàn)Scroll 數(shù)據(jù)無(wú)限滾動(dòng)功能

    今天小編就為大家分享一篇vue和iview實(shí)現(xiàn)Scroll 數(shù)據(jù)無(wú)限滾動(dòng)功能,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-10-10
  • VUE3?Vite打包后動(dòng)態(tài)圖片資源不顯示問(wèn)題解決方法

    VUE3?Vite打包后動(dòng)態(tài)圖片資源不顯示問(wèn)題解決方法

    這篇文章主要給大家介紹了關(guān)于VUE3?Vite打包后動(dòng)態(tài)圖片資源不顯示問(wèn)題的解決方法,可能是因?yàn)樵诓渴鸷蟮姆?wù)器環(huán)境中對(duì)中文文件名的支持不完善,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-09-09
  • vue element實(shí)現(xiàn)將表格單行數(shù)據(jù)導(dǎo)出為excel格式流程詳解

    vue element實(shí)現(xiàn)將表格單行數(shù)據(jù)導(dǎo)出為excel格式流程詳解

    這篇文章主要介紹了vue element實(shí)現(xiàn)將表格單行數(shù)據(jù)導(dǎo)出為excel格式流程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧
    2022-12-12
  • Vue-Cli 3.0 中配置高德地圖的兩種方式

    Vue-Cli 3.0 中配置高德地圖的兩種方式

    這篇文章主要介紹了Vue-Cli 3.0 中配置高德地圖的兩種方式,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-06-06
  • vue3封裝ECharts組件詳解

    vue3封裝ECharts組件詳解

    前端開(kāi)發(fā)需要經(jīng)常使用ECharts圖表渲染數(shù)據(jù)信息,在一個(gè)項(xiàng)目中我們經(jīng)常需要使用多個(gè)圖表,選擇封裝ECharts組件復(fù)用的方式可以減少代碼量,增加開(kāi)發(fā)效率。感興趣的可以閱讀一下本文
    2023-04-04
  • Vue中常用rules校驗(yàn)規(guī)則(實(shí)例代碼)

    Vue中常用rules校驗(yàn)規(guī)則(實(shí)例代碼)

    這篇文章主要介紹了Vue中常用rules校驗(yàn)規(guī)則,本文通過(guò)實(shí)例代碼個(gè)大家介紹了一些校驗(yàn)方法,需要的朋友可以參考下
    2019-11-11

最新評(píng)論

昭平县| 商河县| 璧山县| 黄平县| 迁西县| 合水县| 尖扎县| 阿拉尔市| 荔浦县| 云南省| 庐江县| 高淳县| 莱芜市| 纳雍县| 克什克腾旗| 马边| 铜梁县| 汕头市| 绥中县| 孝昌县| 称多县| 肇庆市| 柳江县| 博客| 连云港市| 应城市| 治县。| 达日县| 临海市| 富阳市| 拜城县| 台东县| 顺平县| 南投市| 汤原县| 广西| 南华县| 鹿邑县| 扶余县| 平安县| 夹江县|