【Vue】探索对象属性变动在Vue中的具体表现

1,298 阅读3分钟

前言

对象作为JavaScript的一种数据类型,拥有键值对构成的属性。

Vue的文档中提到,“由于JavaScript的限制,Vue不能检测对象属性的添加或删除”。

所以我探索了一下对象属性变动在Vue中的具体表现。

属性值更新

定义一个对象obj,拥有一个属性count,值为1

设置一个按钮,每次点击对obj.count的值进行+1操作

<template>
<div>
    <ul>
        <li>count:{{obj.count}}</li>
    </ul>
    <button @click="plus()">+1</button>
</div>
</template>
<script>
export default {
    data () {
        return {
            obj: {
                count: 1
            }
        }
    },
    methods: {
        plus () {
            this.obj.count++
        }
    }
}
</script>

结果发现,当属性值+1能正常触发DOM元素更新

此时,将obj的count属性值稍加改动,同样设置count为对象,且设置count的属性val,值为1。最后数据如下所示

data () {
    return {
        obj: {
            count: {
                val: 1
            }
        }
    }
}

同时模板和方法做对应修改

<ul>
    <li>val:{{obj.count.val}}</li>
</ul>

methods: {
    plus () {
        this.obj.count.val++
    }
}

结果,对象中属性的属性同样可以触发DOM元素更新

属性增减

此时,更换按钮操作。

添加一个按钮,点击时,为obj新增一个total属性值

再添加一个按钮,点击时,删除obj的count属性

<template>
<div>
    <ul>
        <li v-for="(val, key) in obj">{{key}}:{{val}}</li>
    </ul>
    <button @click="add()">add prop</button>
    <button @click="del()">del prop</button>
</div>
</template>
<script>
export default {
    data () {
        return {
            obj: {
                count: 1
            }
        }
    },
    methods: {
        add () {
            this.obj['total'] = 2

            console.log(this.obj)
        },
        del () {
           delete this.obj['count']

           console.log(this.obj)
        }
    }
}
</script>

结果和官网提示的一样,对象属性的新增与删除不会被检查到,所以DOM元素没有被更新

那么,如果在实际开发中遇到这种情况,我们需要DOM元素被更新怎么办?

解决方法

现提供两种解决方法以供参考。

方法一:Vue文档中提到的,使用Vue.set(vue对象实例中使用vm.$set)为对象新增属性,例如为obj新增total属性,可以修改为

 methods: {
    add () {
        this.$set(this.obj, 'total', 2)

        console.log(this.obj)
    }
}

使用Vue.set为对象添加的属性为响应式属性,所以可以正常触发DOM元素更新

方法二:比较简单粗暴,别更新什么属性了,直接把整个对象都替换掉。

methods: {
    add () {
        let temp = Object.assign({}, this.obj)

        temp['total'] = 2

        this.obj = temp

        console.log(this.obj)
    }
}

先通过Object.assign克隆一个临时对象,修改临时对象的属性,再将临时对象赋为obj。 此时的obj相当于更新了一个新值,所以触发了DOM元素更新。

方法二还有一个变种方法,实现方式不是通过克隆obj对象,而是先将obj赋一个空对象,再最终修改的对象值。

methods: {
    add () {
        let temp = this.obj

        this.obj = {}

        temp['total'] = 2

        this.obj = temp

        console.log(this.obj)
    }
}

方法一和方法二的性能,我没有做过对比,且方法二的变种方法有点耍小聪明的嫌疑,我都写出来仅供大家参考。

看起来对象的属性变化就讲完了,但实际开发中时常会遇到一些更复杂的情况。

后面还会继续补充开发中遇到的例子。