服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服务器之家 - 编程语言 - JavaScript - vue.js - vue数据响应式原理重写函数实现数组响应式监听

vue数据响应式原理重写函数实现数组响应式监听

2023-05-17 14:18-耿瑞- vue.js

Vue的通过数据劫持的方式实现数据的双向绑定,即使用Object.defineProperty()来实现对属性的劫持,但是Object.defineProperty()中的setter是无法直接实现数组中值的改变的劫持行为的,需要的朋友可以参考下

output.js代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { observe } from "./dataResp"
const output = () => {
    var obj = {
        data: {
            data: {
                map: {
                    dom: {
                        isgin: true
                    }
                },
                arg: 13
            },
            name: "小猫猫"
        },
        bool: [1,2,3,4]
    };
    observe(obj);
    obj.bool.push(7);
    document.getElementById("text").innerHTML = obj.data.name;
}
export default output

运行结果如下

vue数据响应式原理重写函数实现数组响应式监听

很明显 我们数组并捕获不到 push方法 除了 push 很多数组方法都捕获不到

首先 我们来看几个方法 分别是

vue数据响应式原理重写函数实现数组响应式监听

这几个方法执行 说明 当前数组被改写了内容

那么 我们可以去改写这七个方法 我们在案例 src目录下创建 Arrays.js 然后 大家先要知道 这些方法被定义在哪里? Array.prototype Array是数组类型的一个类对象 这些方法就定义在Array的原型链上 所以 大家才能通过 数组.这些方法 去调用他们 而我们要做的就是 重写这些方法 要做的就是 调用原来的方法 然后 在后面再去做自己需要做的响应式的事情

我们先在src下创建一个def.js 然后将之前写在dataResp.js中的def放进def.js来

?
1
2
3
4
5
6
7
8
9
10
export const def = function(obj,key,value,enumerable) {
    Object.defineProperty(obj,key,{
        value,
        enumerable,
        //true  设为可写
        writable: true,
        //true  设为可被删除
        configurable: true
    });
}

然后 将dataResp.js中的def方法干掉 然后 dataResp.js引入一下def.js的 def方法

?
1
import {<!--{C}%3C!%2D%2D%20%2D%2D%3E--> def } from './def.js';

这个是我之前没想清楚 抱歉

然后 我们在Arrays.js中编写代码如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { def } from './def.js';
const arrayPrototype = Array.prototype;
export const arrayMethods = Object.create(arrayPrototype);
const redefineArrayMethod = [
    'push',
    'pop',
    'shift',
    'unshift',
    'splice',
    'sort',
    'reverse'
]
redefineArrayMethod.forEach(item =>{
    const backupFunction = arrayPrototype[item];
    def(arrayMethods,item,function(){
        backupFunction.apply(this, arguments);
        console.log('数组执行了',item,'操作,值被修改为',this);
    },false);
})

这里 我们先定义了redefineArrayMethod变量 他的值是一个数组 对应下面每一个字符串下标 都是这些改变数组结构的函数关键字

然后定义 arrayPrototype 存一下Array的 原型链 prototype 因为 这些函数就在上面

然后 创建arrayMethods 记录创建数组 并将arrayPrototype

最后 循环redefineArrayMethod 对应每一次下标循环 拿到都是一个数组方法关键字 第一次拿到’push’ 第二次’pop’

然后 我们的响应式代码就可以写在这里 首先 我们先

?
1
const backupFunction = arrayPrototype[item];

备份一下原来的方法 因为 你别重写之后 方法原有的逻辑没有了啊 是不是

你别说 push我监听一下 写完 push都加不进去东西了 那响应个啥 这BUG了啊

然后 我们调用def

第一个参数是 arrayMethods 就是被创建的对象

第二个 这里传的是 当前循环的内容 就是方法名数组下标 看着是第几次循环 第一次 push 第二次 pop 第三次 shift 依次类推

第四个参数 不用说 这东西你们肯定不希望他参与遍历吧 果断false 至于第三个 是他的值 我们要改写这个函数啊 就写了这个函数新的内容

?
1
backupFunction.apply(this, arguments);

先把我们备份的之前的函数内容执行了 就是 比如 push 我们先用执行参数帮他把push应该有的增加下标的逻辑执行了 this不用说 肯定要的 当前对象 然后arguments代表我们当前函数拿到的所有参数 全部给了backupFunction.apply当参数 就是保证参数不要少了

然后下面的代码 我们就捕获被改变的这个事情

然后 我们改写 dataResp.js中的Observer类代码如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Observer{
    constructor(value) {
        //相当于  给拿到的对象  其中的__ob__绑定 值为thsi,在类中用this 表示取实例本身给__ob__赋值  最后一个enumerable为false 表示属性不参与for遍历
        def(value,'__ob__',this,false);
        if(Array.isArray(value)){
            Object.setPrototypeOf(value, arrayMethods);
        }
        this.walk(value);
    }
    walk(value) {
        for(let key in value){
            defineReactive(value,key);
        }
    }
}

就是 监听到 如果是数字类型 调用一下 Object.setPrototypeOf 监听

然后 我们再次运行代码

vue数据响应式原理重写函数实现数组响应式监听

可以看到 我们重写的方法 就起效了 push被成功捕获 并输出了语句

vue数据响应式原理重写函数实现数组响应式监听

到此这篇关于vue数据响应式原理重写函数实现数组响应式监听的文章就介绍到这了,更多相关vue重写函数实现数组响应式监听内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/weixin_45966674/article/details/130311546

延伸 · 阅读

精彩推荐
  • vue.js浅析vue中的nextTick

    浅析vue中的nextTick

    这篇文章主要介绍了vue中nextTick的相关资料,帮助大家更好的理解和使用vue框架,感兴趣的朋友可以了解下...

    Leise7622021-12-21
  • vue.jsvue-router钩子函数实现路由守卫

    vue-router钩子函数实现路由守卫

    这篇文章主要介绍了vue-router钩子函数实现路由守卫,对vue感兴趣的同学,可以参考下...

    有梦想的咸鱼前端5102022-03-10
  • vue.jsVue router-view和router-link的实现原理

    Vue router-view和router-link的实现原理

    这篇文章主要介绍了Vue router-view和router-link的实现原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友...

    mengyuhang48794472022-02-13
  • vue.jsvue项目中openlayers绘制行政区划

    vue项目中openlayers绘制行政区划

    这篇文章主要为大家详细介绍了vue项目中openlayers绘制行政区划,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    吞肥皂吐泡泡11522021-12-18
  • vue.js详解vite2.0配置学习(typescript版本)

    详解vite2.0配置学习(typescript版本)

    这篇文章主要介绍了详解vite2.0配置学习(typescript版本),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们...

    fangzhou_lu6612022-01-22
  • vue.js详解vue3中渲染函数的非兼容变更

    详解vue3中渲染函数的非兼容变更

    这篇文章主要介绍了详解vue3中渲染函数的非兼容变更,帮助大家更好的理解和学习使用vue框架,感兴趣的朋友可以了解下...

    月岛蘑菇11332022-02-15
  • vue.jsVue中避免滥用this去读取data中数据

    Vue中避免滥用this去读取data中数据

    这篇文章主要介绍了Vue中避免滥用this去读取data中数据的的相关资料,帮助大家更好的理解和学习使用vue框架,感兴趣的朋友可以了解下...

    红尘炼心12322022-01-25
  • vue.jsvue下拉刷新组件的开发及slot的使用详解

    vue下拉刷新组件的开发及slot的使用详解

    这篇文章主要介绍了vue下拉刷新组件的开发及slot的使用详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需...

    行舟客7012021-12-16