vue实例、组件未及时渲染问题分析及解决方案

前言

在开发过程中,我们时常会遇到这样一种情况:当vue的data里边有对象或者数组(数组里边的值是对象)时,后续向对象中添加新的属性是不会更新到视图的。

根据官方文档定义:如果在实例创建之后添加新的属性到实例上,它不会触发视图更新

当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter

受现代 JavaScript 的限制 (以及废弃 Object.observe),Vue 不能检测到对象属性的添加或删除。由于 Vue 会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。

对象

看一下示例:

data中的变量userInfo是一个对象,初始化时只有一个属性name,当点击添加性别时会给userInfo对象添加一个属性sex,页面能识别到吗

<template>
  		<p>{{userInfo.name}}</p>
        <p v-if="userInfo.sex">{{userInfo.sex}}</p>
        <button @click="updateName">修改userInfo</button>
        <button @click="addSex">添加性别</button>
</template>
<script>
    data(){
        userInfo:{name:'小明'}
    },
    methods:{
        updateName(){
            this.userInfo.name='小红'
        },
        addSex(){
            this.userInfo.sex = '男'
        }
    }
</script>

可以发现,在updateName函数中,我们尝试给userInfo对象修改name值并成功修改,但sex属性虽然添加成功了,但是没有生成对应的getter/setter函数,不会触发视图响应

分析

  • 名字修改成功是因为vue初始化时为对象的属性建立 了getter/setter函数,可以监测数据变化并挂载到视图上
  • 而新增的sex属性由于错过了建立getter/setter阶段,即使在userInfo对象中添加成功,但由于没有setter函数,无法响应到视图上

解决方法

方法一:$forceUpdate()

迫使 Vue 实例重新渲染。注意它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件。

methods:{
  updateName(){
    this.userInfo.sex='男'		
    this.$forceUpdate();	
  }
}

方法二:Vue.set(object, key, value)

methods:{
  updateName(){
    this.$set(this.userInfo,'sex,'男');
  }
}

数组

上面的例子反映的是给对象添加属性时的问题,数组同样有类似的问题,请看下面的例子

<body>
    <div id="app">
        <p>{{userInfo.name}}</p>
        <p v-if="userInfo.sex">{{userInfo.sex}}</p>
        <ul>
            <li v-for="(item,index) in hobbies" :key='index'>{{item}}</li>
        </ul>
        <button @click="update">修改爱好</button>
    </div>
<script>
    let vm = new Vue({
        el:'#app',
        data: {
            userInfo:{name:'小明'},
            hobbies:['抽烟','喝酒','烫头']
        },
        methods:{
            update(){
                this.hobbies[2] = '读书'
            }
        }
    })
</script>
</body>

点击修改爱好按钮后页面并没有修改,打开控制台发现值已修改

解决方法

一、使用vue提供的更新数组的方法

vue给我们提供了它封装后的可用于对数组进行增删改查操作的方法
Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

上面的例子

update(){
    //参数分别是:开始索引,是否删除(0:添加 1:删除),修改后的值
    this.hobbies.splice(2,1,'读书')
},

使用封装后的方法则可以成功渲染到视图

二、Vue.set()

update(){
    //参数分别是:对象,索引,修改后的值
     Vue.set(this.hobbies,2,'读书')
},

三、this.$forceUpdate()

 update() {
     this.hobbies[2] = '读书'
     this.$forceUpdate()
 },
posted @ 2021-03-24 13:16  至安  阅读(1151)  评论(0)    收藏  举报