Vue 中 $set() 与 Vue.set() 原理及使用

简介: Vue 中 $set() 与 Vue.set() 原理及使用

1. 前言

问题: 在使用 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>
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>

当点击按钮后页面:

2020062310470442.png

当点击按钮后控制台:

2020062310470442.png

原因:

受 ES5 的限制,Vue.js 不能检测到对象属性的添加或删除。因为 Vue.js 在初始化实例时将属性转为 getter/setter,所以 属性必须在 data 对象上才能让 Vue.js 转换它,才能让它是响应的。

因此:

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 即可;

2. 原理

每个组件实例都有相应的 watcher 实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。

2020062310470442.png

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

3. $set() 与 Vue.set() 的使用

3.1 通过 Vue.set() 改写

语法:

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>

当点击按钮后页面:

2020062310470442.png

当点击按钮后控制台:

2020062310470442.png

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">
      <span>年龄:{{item.age}}</span>
      <span>地点:{{item.address}}</span>
    </div>
  <button @click="btn()">修改</button>
  </div>
</template>
<script>
export default {
  name: 'Home',
  data(){
    return{
      student:{
        name:'张三',
      },
      items:[
        {
          age:12,
          address:'南京',
        },{
          age:15,
          address:'深圳',
        },{
          age:20,
          address:'上海',
        }
      ]
    }
  },
  methods:{
    btn(){
      this.$set(this.student, 'age', 18);
      this.$set(this.items, 1, {age:22, address:'武汉'});
      console.log(this.student,this.items);
    }
  }
}
</script>

当点击按钮后页面:

2020062310470442.png

当点击按钮后控制台:

2020062310470442.png

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原型上。




相关文章
|
2月前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
45 3
|
4月前
|
JavaScript 算法 编译器
vue3 原理 实现方案
【8月更文挑战第15天】vue3 原理 实现方案
45 1
|
28天前
|
缓存 JavaScript 搜索推荐
Vue SSR(服务端渲染)预渲染的工作原理
【10月更文挑战第23天】Vue SSR 预渲染通过一系列复杂的步骤和机制,实现了在服务器端生成静态 HTML 页面的目标。它为提升 Vue 应用的性能、SEO 效果以及用户体验提供了有力的支持。随着技术的不断发展,Vue SSR 预渲染技术也将不断完善和创新,以适应不断变化的互联网环境和用户需求。
41 9
|
3月前
|
缓存 JavaScript 前端开发
「offer来了」从基础到进阶原理,从vue2到vue3,48个知识点保姆级带你巩固vuejs知识体系
该文章全面覆盖了Vue.js从基础知识到进阶原理的48个核心知识点,包括Vue CLI项目结构、组件生命周期、响应式原理、Composition API的使用等内容,并针对Vue 2与Vue 3的不同特性进行了详细对比与讲解。
「offer来了」从基础到进阶原理,从vue2到vue3,48个知识点保姆级带你巩固vuejs知识体系
|
2月前
|
JavaScript UED
Vue双向数据绑定的原理
【10月更文挑战第7天】
|
4月前
|
JavaScript 前端开发 索引
vue之$set
vue之$set
|
2月前
|
JavaScript 前端开发 API
vue3知识点:Vue3.0中的响应式原理和 vue2.x的响应式
vue3知识点:Vue3.0中的响应式原理和 vue2.x的响应式
25 0
|
3月前
vue2的响应式原理学“废”了吗?继续观摩vue3响应式原理Proxy
该文章对比了Vue2与Vue3在响应式原理上的不同,重点介绍了Vue3如何利用Proxy替代Object.defineProperty来实现更高效的数据响应机制,并探讨了这种方式带来的优势与挑战。
vue2的响应式原理学“废”了吗?继续观摩vue3响应式原理Proxy
|
3月前
|
缓存 JavaScript 容器
vue动态组件化原理
【9月更文挑战第2天】vue动态组件化原理
47 2
|
3月前
|
开发框架 JavaScript 前端开发
手把手教你剖析vue响应式原理,监听数据不再迷茫
该文章深入剖析了Vue.js的响应式原理,特别是如何利用`Object.defineProperty()`来实现数据变化的监听,并探讨了其在异步接口数据处理中的应用。
下一篇
无影云桌面