问题: 在使用 vue 进行开发的过程当中,可能会遇到一种状况:当生成vue实例后,再次给数据赋值时,有时候并不会自动更新到视图上去。也就是 若是在实例建立以后添加新的属性到实例上,它不会触发视图更新。javascript
案例:css
<template> <div class="home"> <div>{{student}}</div> <div v-for="(item,index) in items" :key="index">{{item}}</div> <button @click="btn()">修改</button> </div> </template> <script> export default { name: 'Home', data(){ return{ student:{ name:'张三', }, items:[1, 2, 3], } }, methods:{ btn(){ this.student.age = 18; this.items[1] = 'two'; console.log(this.student,this.items); } } } </script>
当点击按钮后页面:vue
当点击按钮后控制台:java
缘由:
受 ES5 的限制,Vue.js 不能检测到对象属性的添加或删除。由于 Vue.js 在初始化实例时将属性转为 getter/setter,因此 属性必须在 data 对象上才能让 Vue.js 转换它,才能让它是响应的。api
所以:
Vue 不能检测如下变更的数组:
当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
当你修改数组的长度时,例如:vm.items.length = newLength
eg:
使用 this.arr[0] 去更新 array 的内容,视图没有刷新
使用 Vue.set(this.arr, 0, !this.arr[0]) 去更新 array 的内容,视图被刷新
使用 this.arr[0] = !this.arr[0] 和 this.obj.a = !this.obj.a 同时更新,视图被刷新数组
结论:
若是方法里面单纯的更新数组 Array 的话,要使用 Vue.set();
若是方法里面同时有数组和对象的更新,直接操做 data 便可;ide
每一个组件实例都有相应的 watcher 实例对象,它会在组件渲染的过程当中把属性记录为依赖,以后当依赖项的 setter 被调用时,会通知 watcher 从新计算,从而导致它关联的组件得以更新。
受现代 JavaScript 的限制 (并且 Object.observe 也已经被废弃),Vue 不能检测到对象属性的添加或删除。因为 Vue 会在初始化实例时对属性执行 getter/setter 转化过程,因此属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。函数
3.1 经过 Vue.set() 改写
语法:this
Vue.set( target, propertyName/index, value ) 参数: {Object | Array} target {string | number} propertyName/index {any} value 返回值:设置的值。 用法: 向响应式对象中添加一个 property,并确保这个新 property 一样是响应式的,且触发视图更新。 它必须用于向响应式对象上添加新 property,由于 Vue 没法探测普通的新增 property (好比 this.myObject.newProperty = 'hi') 注意: 对象不能是 Vue 实例,或者 Vue 实例的根数据对象。
<template> <div class="home"> <div>{{student}}</div> <div v-for="(item,index) in items" :key="index">{{item}}</div> <button @click="btn()">修改</button> </div> </template> <script> import Vue from 'vue' // 别忘了引入 export default { name: 'Home', data(){ return{ student:{ name:'张三', }, items:[1, 2, 3], } }, methods:{ btn(){ Vue.set(this.student, 'age', 18); Vue.set(this.items, 1, 'two'); console.log(this.student,this.items); } } } </script>
当点击按钮后页面:
当点击按钮后控制台:spa
3.2 经过 $set() 改写
语法:
vm.$set( target, propertyName/index, value ) 参数: {Object | Array} target {string | number} propertyName/index {any} value 返回值:设置的值。 用法: 这是全局 Vue.set 的别名。 参考:Vue.set
<template> <div class="home"> <div>{{student}}</div> <div v-for="(item,index) in items" :key="index">{{item}}</div> <button @click="btn()">修改</button> </div> </template> <script> export default { name: 'Home', data(){ return{ student:{ name:'张三', }, items:[1, 2, 3], } }, methods:{ btn(){ this.$set(this.student, 'age', 18); this.$set(this.items, 1, 'two'); console.log(this.student,this.items); } } } </script>
当点击按钮后页面:
当点击按钮后控制台:
3.3 Vue.set() 和 this.$set() 的区别
Vue.set() 源码:
import { set } from '../observer/index' ... Vue.set = set ...
this.$set() 源码
import { set } from '../observer/index' ... Vue.prototype.$set = set ...
能够发现 Vue.set() 和 this.$set() 这两个 api 的实现原理基本如出一辙,都是使用了set函数。 set 函数是从 …/observer/index 文件中导出的。 区别: Vue.set( ) 是将 set 函数绑定在 Vue 构造函数上,this.$set() 是将 set 函数绑定在 Vue原型上。