在vue中,改变某个对象的值时(如数组中的某一项或者对象的某个属性),vue并不会触发dom更新,这时就需要我们自己手动来操作。

方法一:强制刷新

// 此行为会重新渲染整个dom,除数据层次太多外,不建议使用
this.$forceUpdate();

 方法二:对于已经创建的实例,Vue 不允许动态添加根级别的响应式属性。但是,可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式属性。如:

data() {
    // 数组
    array: [1, 2, 3, 4];
    // 对象
    obj: {name: "test"},
}
......

// 这种方式赋值并不会触发dom并自动更新
// this.array[0] = 5;

// 改为此种方式赋值则会触发更新,
// 参数1:要修改的数组,    参数2:要修改的数组的索引,    参数3:修改后的值
this.$set(this.array, 0, 5);




// this.obj.name = "张三";

// 参数1:要修改的对象,    参数2:要修改的对象的属性名,    参数3:修改后的值
this.$set(this.obj, "name", "张三");

 

以下是出现这种情况的原因:

出现这种情况的原因是由于vue2.x的基本原理决定的。vue的基本原理是通过Object.defineProperty重写变量的get和set方法来实现监听变量的改变和通知页面重新渲染的。

这里就要了解一下Object.defineProperty,以下直接拷贝的官网文档。

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

Object.defineProperty(obj, prop, descriptor)

obj: 要定义属性的对象。

prop: 要定义或修改的属性的名称或 Symbol 。

descriptor: 要定义或修改的属性描述符。

假如你在vue中定义了一个对象:objTest: {name: "test"},

vue在created之前会重写objTest对象中name的get和set:

// 先把原来的obj深拷贝一份
var objCopy = JSON.parse(JSON.stringfy(this.obj));
var newObjTest = Object.defineProperty(objTest, 'name', {
        get: function () {
            // 返回objCopy的name,如果返回obj.name会死循环
            return objCopy.name;
        },
        set: function (newValue) {
            // 把objCopy的name属性重新赋值
            objCopy.name = newValue;
            // 去通知页面obj的name的值变了,该渲染页面了
            ......
        }
    })

从上面的例子可以看出,当我们给obj.name属性赋值的时候,会走我们重新定义的set方法,并让页面重新渲染,但是为什么有时候却不行呢?这就是Object.defineProperty的不足之处了,因为在vue中它只会遍历已有的对象及其属性,未定义的属性vue是不会重写get和set的方法的。

所以如果你在data中没有定义某个对象属性,而在后续的操作中添加了新的属性时,页面是不会重新渲染的。

Logo

前往低代码交流专区

更多推荐