Vue2 响应式系统之深度响应

 更新时间:2022年04月12日 20:17:54   作者:windliang  
这篇文章主要介绍了Vue2 响应式系统之深度响应,文章基于Vue2 响应式系统的相关资料展开对Vue2 深度响应的介绍,需要的小伙伴可以参考一下

1、场景

import { observe } from "./reactive";
import Watcher from "./watcher";
const data = {
    text: {
        innerText: {
            childText: "hello",
        },
    },
};
observe(data);
const updateComponent = () => {
    console.log(data.text.innerText.childText);
};

new Watcher(updateComponent);
data.text.innerText.childText = "liang";

我们的响应式系统到现在还没有支持属性是对象时候的响应,因此我们改变 的时候不会有任何输出。childText

我们只收集了 的依赖,所以如果想要响应的话必须给 整个赋值为一个新对象。data.textdata.text

import { observe } from "./reactive";
import Watcher from "./watcher";
const data = {
    text: {
        innerText: {
            childText: "hello",
        },
    },
};
observe(data);
const updateComponent = () => {
    console.log(data.text.innerText.childText);
};

new Watcher(updateComponent);
data.text = {
    innerText: {
        childText: "liang",
    },
};

image-20220405115503890

我们当然不希望每次都赋值整个对象,我们需要做一些修改,把嵌套的对象也变成响应式的。

2、方案

我们只需要在给某个 重写 和 之前,把它的 就像上边给 调用 函数一样,也调用一次 函数即可。keygetsetvaluedataobserveobserve

同时提供 参数,留下扩展,让外界决定是否需要深度响应。shallow

/*******************新增 shallow*******************/
export function defineReactive(obj, key, val, shallow) {
/****************************************************/
    const property = Object.getOwnPropertyDescriptor(obj, key);
    // 读取用户可能自己定义了的 get、set
    const getter = property && property.get;
    const setter = property && property.set;
    // val 没有传进来话进行手动赋值
    if ((!getter || setter) && arguments.length === 2) {
        val = obj[key];
    }
    const dep = new Dep(); // 持有一个 Dep 对象,用来保存所有依赖于该变量的 Watcher
    /*******************新增****************************/
    !shallow && observe(val);
  	/******************************************************/
    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: function reactiveGetter() {
            const value = getter ? getter.call(obj) : val;
            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;
            }
            dep.notify();
        },
    });
}

同时,在 函数中,传进来的 不是对象的话我们直接 。observevaluereturn

/*
util.js
export function isObject(obj) {
    return obj !== null && typeof obj === "object";
}
*/
export function observe(value) {
    if (!isObject(value)) {
        return;
    }
    let ob = new Observer(value);
    return ob;
}

3、场景2

import { observe } from "./reactive";
import Watcher from "./watcher";
const data = {
    text: {
        innerText: {
            childText: "hello",
        },
    },
};
observe(data);
const updateComponent = () => {
    console.log(data.text.innerText.childText);
};

new Watcher(updateComponent);

data.text.innerText.childText = "liang";
data.text = {
    innerText: {
        childText: "liang2",
    },
};

data.text.innerText.childText = "liang3";

可以一分钟想一下上边会输出什么。

new Watcher(updateComponent); ,执行一次 输出 。updateComponenthello

data.text.innerText.childText = "liang"; ,我们已经解决了属性是对象的情况,因此这里也会输出 。liang

data.text = {
    innerText: {
        childText: "liang2",
    },
};

上边代码就是文章最开头的方法,因此也会触发函数执行,输出 。liang2

data.text.innerText.childText = "liang3"; 最后这句会执行吗?

答案是否定的了,因为我们的 赋值为了一个新对象,但这个新对象我们并没有将其设置为响应式的。data.text

因此我们需要在 的时候把对象也设置为响应式的。set

/**
 * Define a reactive property on an Object.
 */
export function defineReactive(obj, key, val, shallow) {
    const property = Object.getOwnPropertyDescriptor(obj, key);
    // 读取用户可能自己定义了的 get、set
    const getter = property && property.get;
    const setter = property && property.set;
    // val 没有传进来话进行手动赋值
    if ((!getter || setter) && arguments.length === 2) {
        val = obj[key];
    }
    const dep = new Dep(); // 持有一个 Dep 对象,用来保存所有依赖于该变量的 Watcher

    let childOb = !shallow && observe(val);
    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: function reactiveGetter() {
            const value = getter ? getter.call(obj) : val;
            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;
            }
          /******新增 *************************/
            childOb = !shallow && observe(newVal);
           /************************************/
            dep.notify();
        },
    });
}

4、总结

通过递归解决了属性是对象的依赖,可以为未来数组的依赖留下基础。

到此这篇关于Vue2 响应式系统之深度响应的文章就介绍到这了,更多相关Vue2 深度响应内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • VUE项目初建和常见问题总结

    VUE项目初建和常见问题总结

    在本篇文章里小编给大家整理的是关于VUE 项目初建和常见问题以及相关知识点内容,有需要的朋友们学习下。
    2019-09-09
  • 解决antd datepicker 获取时间默认少8个小时的问题

    解决antd datepicker 获取时间默认少8个小时的问题

    这篇文章主要介绍了解决antd datepicker 获取时间默认少8个小时的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-10-10
  • Vue 解决在element中使用$notify在提示信息中换行问题

    Vue 解决在element中使用$notify在提示信息中换行问题

    这篇文章主要介绍了Vue 解决在element中使用$notify在提示信息中换行问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11
  • Vuejs第一篇之入门教程详解(单向绑定、双向绑定、列表渲染、响应函数)

    Vuejs第一篇之入门教程详解(单向绑定、双向绑定、列表渲染、响应函数)

    组件(Component)是 Vue.js 最强大的功能之一。接下来给大家介绍vuejs单向绑定、双向绑定、列表渲染、响应函数的相关知识,非常不错,感兴趣的朋友一起看看吧
    2016-09-09
  • 详解vue中async-await的使用误区

    详解vue中async-await的使用误区

    这篇文章主要介绍了vue中async-await的使用误区,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-12-12
  • 学习Vite的原理

    学习Vite的原理

    这篇文章主要介绍了Vite的原理,Vite是一个更轻、更快的web应用开发工具,面向现代浏览,Vite创建的项目是一个普通的Vue3应用,相比基于Vue-cli创建的应用少了很多配置文件和依赖,下面基于Vite相关资料内容,需要的朋友可以参考一下
    2022-02-02
  • vue-cli实现异步请求返回mock模拟数据

    vue-cli实现异步请求返回mock模拟数据

    网上有不少使用mockjs模拟数据的文章,但基本都是本地拦截请求返回数据,本文主要介绍了vue-cli实现异步请求返回mock模拟数据,文中根据实例编码详细介绍的十分详尽,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • webpack vue项目开发环境局域网访问方法

    webpack vue项目开发环境局域网访问方法

    下面小编就为大家分享一篇webpack vue项目开发环境局域网访问方法,具有很好的参考价值,希望对大家有所帮助,一起跟随小编过来看看吧
    2018-03-03
  • vue实现tab切换的3种方式及切换保持数据状态

    vue实现tab切换的3种方式及切换保持数据状态

    这篇文章主要给大家介绍了关于vue实现tab切换的3种方式及切换保持数据状态的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05
  • vue axios封装及API统一管理的方法

    vue axios封装及API统一管理的方法

    这篇文章主要介绍了vue axios封装以及API统一管理 ,需要的朋友可以参考下
    2019-04-04

最新评论