Vue.set(),this.$set()与Vue.nextTick()

前言

平时做项目时会经常对数组和对象进行数据更新操作,而有时数据并没有及时更新,这时我们会用Vue.set(),this.$set()等方法让数据及时更新。

Vue.set(),this.$set()

<body>
    <div id="app">
        obj:{{obj}}
        <ul>
	        <li v-for="(item,index) in arr" v-bind:key="item">
	            arr[{{index}}]:{{item}}
	        </li>
        </ul>
   </div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>    
<script>
    var vm = new Vue({
        el:"#app",
        data:{
            arr:[1,2],
            obj:{
                a:3
            }
        }
    })
</script>

此时页面显示的数据如下图:
Vue.set(),this.$set()与Vue.nextTick()_第1张图片
添加以下代码,发现数据并没有改变:

vm.$data.arr[0] = 10; //页面不会重新渲染
vm.$data.obj.b = 15; //页面不会重新渲染

而添加以下代码,数据可以改变:

vm.$data.obj.a = 20;  //页面可以重新渲染

这是因为受现代 JavaScript 的限制,Vue 无法检测到对象属性的添加或删除。
由于 Vue 会在初始化实例时对属性执行 getter/setter 转化,所以属性必须在 data 对象上存在才能让 Vue 将它转换为响应式的。
而vm.$data.arr[0] = 10之所以不会重新渲染,是因为vue2在处理数组响应式变化时,采用覆盖 push、pop、shift、unshift、splice、reverse、sort 这七个数组方法,并将其处理为可以发送更新通知的函数实现的,故不能直接修改对应下标的值。

//vm.$data.obj.a 是响应式的
//vm.$data.obj.b 是非响应式的

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

Vue.set(vm.$data.arr,0,10)   //页面可以重新渲染
Vue.set(vm.$data.obj,'b',15) //页面可以重新渲染

还可以使用 vm.$set 实例方法,这也是全局 Vue.set 方法的别名

vm.$set(vm.$data.arr,0,10)   //页面可以重新渲染
vm.$set(vm.$data.obj,'b',15) //页面可以重新渲染

页面重新渲染后的效果图:
Vue.set(),this.$set()与Vue.nextTick()_第2张图片

Vue.nextTick()

Vue 在更新 DOM 时是异步执行的。
Vue.nextTick()是基于更新后的DOM状态进行操作。
例如:

<body>
    <div id="app">{{message}}</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            message: '123'
        }
    })
</script>

页面显示为:123。
添加以下代码,更改数据:

vm.message = 'new message' // 更改数据

页面显示为:new message。但该组件不会立即重新渲染。

为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback)。这样回调函数将在 DOM 更新完成后被调用
将打印结果进行对比:

console.log(vm.$el.textContent === 'new message') // false

此时DOM更新还未完成,vm.$el.textContent===‘123’。

Vue.nextTick(function () {
	console.log(vm.$el.textContent === 'new message') // true
})

使用Vue.nextTick(callback),回调函数在 DOM 更新完成后被调用,即此时DOM更新已完成,vm.$el.textContent === ‘new message’。

在组件内使用 vm.$nextTick() 实例方法特别方便,因为它不需要全局 Vue,并且回调函数中的 this 将自动绑定到当前的 Vue 实例上

Vue.component('example', {
  template: '{{ message }}',
  data: function () {
    return {
      message: '未更新'
    }
  },
  methods: {
    updateMessage: function () {
      this.message = '已更新'
      console.log(this.$el.textContent) // => '未更新'
      this.$nextTick(function () {
        console.log(this.$el.textContent) // => '已更新'
      })
    }
  }
})

2.1.0 起新增:如果没有提供回调且在支持 Promise 的环境中,则返回一个 Promise。请注意 Vue 不自带 Promise 的 polyfill,所以如果你的目标浏览器不原生支持 Promise (IE:你们都看我干嘛),你得自己提供 polyfill。

// 修改数据
vm.msg = 'Hello'
// DOM 还没有更新
Vue.nextTick(function () {
  // DOM 更新了
})

// 作为一个 Promise 使用 
Vue.nextTick()
  .then(function () {
    // DOM 更新了
  })

可见Vue深入响应式原理https://cn.vuejs.org/v2/guide/reactivity.html

你可能感兴趣的:(vue,数据更新,this.$set(),nextTick())