Vue深入响应式原理之对象 - 为什么我的修改没有生效?

如有错误望请指出

在开发过程中可能会遇到修改了值,视图未发生更新的情况。

实际上在vue的官方文档中也有描述,见 深入响应式原理

这里会以实际案例讲述

问题重现

下面是一个循环显示对象的vuejs代码(建议有条件的可以直接运行查看效果)

<!DOCTYPE html>
<html lang="en">
<head>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="root">
        <div v-for="(v,k) in obj">{{k}} => {{v}}</div>
        <button @click="setA">赋值A</button>
        <button @click="setB">赋值b</button>
        <button @click="print">打印</button>
    </div>
</body>
<script>
    new Vue({
        el: '#root',
        data() {
            return {
                obj: {
                    a: 1
                }
            }
        },
        methods: {
            setA() {
                this.obj.a = 'new A';
            },
            setB() {
                this.obj.b = 2;
            },
            print() {
                console.log(this.obj)
            }
        }
    });
</script>
</html>

通过浏览器打开后初始状态如下图:
在这里插入图片描述
点击赋值A 后,页面发生了预期的变化,结果如下:
在这里插入图片描述
点击 赋值b 后,此时发现并没有发生预期的变化,html并没有渲染出b => 2这样的内容。
但实际对象确实新增了一个值为2b属性,点击打印验证
在这里插入图片描述

如何解决?

方法一:提前定义

咱们可以很明显的发现差异,a是原来就定义在obj中的,而b不是。
因此第一个方法就是定义一个空值b。如下:

...
...
 data() {
     return {
         obj: {
             a: 1,
             b: null
         }
     }
 }
...
...

方法二:使用 $set

方法一虽然有效,但有时确实存在无法预先知道要新增的属性名或者说懒得(?)。

出现问题的本质是vue不知道新增了一个b属性,vue本身提供了一个$set方法用于解决这个问题,将setB中赋值方法修改。
代码如下:

    setB() {
        // this.obj.b = 2;
        this.$set(this.obj, 'b', 2);
    },

此时再点击赋值b就可以看到html发生了符合预期的变化。

为什么?

要实现在值发生变化时页面也同时发生改变,关键是在于发现值的变化

Vue利用了Object.defineProperty (这里有更详细的描述)。简单的说,使用这个方法可以给对象的某一个属性加上getter/setter方法,之后在读取这个值时会执行getter方法,在设置时会执行setter方法。以此就可以监听到对象属性的存取操作,继而也就能实现html的更新。

因此,当在data中定义完值并返回后,vue会对其中对象(数组的情况暂不考虑)的所有属性,进行递归式的Object.defineProperty
这也是为什么,需要提前定义。因为这个方法并不能监听到对象属性的新增删除

vue作者因此提供了$set$delete 这样的显式操作。以支持响应式。

另外对于数组

对于数组,可以知道能够对数组自身产生变化的方法只有七个。
分别是:push,pop,shift,unshift,splice,sort,reverse
因此vue中对这些方法重新进行了定义,能够在调用这些方法时发现数组的变化。
所以!当以数组下标的方式修改数组时,vue也是发现不了的,这个时候还是得使用$set来解决。

其他:Proxy

在vue3中Object.defineProperty方式被放弃,转而使用Proxy实现对数据的观察。Proxy从能力上是优于Object.defineProperty的,更详细内容的,先自己查查吧。。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值