一.背景

vue初始化实例对象的时候会把属性转位setter/getter。这样数据才会是动态响应的(即data中的数据是动态响应的),vue才能监听到属性的添加,删除,修改(受ES5的限制)。

二.原理

(1)vue.set源码

import { set } from '../observer/index'
...
Vue.set = set
...

(2)this.$set源码

import { set } from '../observer/index'
...
Vue.prototype.$set = set
...

三.区别

(1)Vue.set

1.vue.set可以设置实例创建之后添加的新的特性(即在data中未声明,vue实例创建时beforeCreate之后,created之前,监听data对象数据变,并未初始化vue内部事件)

2.vue.set不允许添加根级响应式属性,只可以嵌套对象添加响应式属性

备注:什么是根级响应式属性

由于vue不允许动态添加根级响应式属性,所以你必须在初始化实例前声明根级响应式属性,哪怕只是一个空值:

var vm = new Vue({
data: {
// 声明 message 为一个空值字符串
message: ''
},
template: '<div>{{ message }}</div>'
})
// 之后设置 `message`
vm.message = 'Hello!'
如果你在data属性中未声明message,vue将警告你渲染函数在试图访问的属性不存在
这样的限制在背后是有技术原因的,它消除了在依赖项跟踪系统中的一类边界情况,也是vue实例在类型检查系统的帮助下运行的更高效。而且在代码可维护性方面也有一点考虑:data对象就像组件状态的概要,提前声明所有的响应式属性,可以让组件代码在以后阅读或其他开发人员阅读时更易于理解。

3.vue.set是将set函数绑定在vue构造函数

(2)this.$set

1.this.$set只能设置实例创建后存在的数据(数据已经在data中)

2.将set函数绑定在vue原型上

四.代码

(1)想要在obj对象里面添加C属性

<template>
  <div class="">
    <input type="text" v-model="obj.a" />
    <input type="text" v-model="obj.b" />
    <input type="text" v-model="obj.c" />
    <hr />
    <button @click="fn">点击出现3</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      obj: {
        a: 1,
        b: 2,
      },
    };
  },
  name: "",
  methods: {
    fn() {
      this.obj.c = 3;
    },
  },
};
</script>

<style scoped></style>

(2)点击完之后的图示

(3)这个时候就可以采用上面介绍的方法 

  1.代码:

<template>
  <div class="">
    <input type="text" v-model="obj.a" />
    <input type="text" v-model="obj.b" />
    <input type="text" v-model="obj.c" />
    <hr />
    <button @click="fn">点击出现3</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      obj: {
        a: 1,
        b: 2,
      },
    };
  },
  name: "",
  methods: {
    fn() {
      this.$set(this.obj, "c", 3);
    },
  },
};
</script>

<style scoped></style>

里面用到的方法是:this.$set(第一个参数是要添加的对象,第二个是key(需要要用引号包裹起来),第三个是需要添加的值)

2.图示:

 

 实现了响应式

(3)this的指向问题

 打印this出现的结果是:

 可以看出打印出来的结果是一个组件的实例,原型链条的查找机制

 因此可以访问到this.$set这个方法。

(4)接下来使用Vue.set来实现响应式

 1.代码:

<template>
  <div class="">
    <input type="text" v-model="obj.a" />
    <input type="text" v-model="obj.b" />
    <input type="text" v-model="obj.c" />
    <hr />
    <button @click="fn">点击出现3</button>
  </div>
</template>

<script>
import Vue from "vue";
export default {
  data() {
    return {
      obj: {
        a: 1,
        b: 2,
      },
    };
  },
  name: "",
  methods: {
    fn() {
      Vue.set(this.obj, "c", 3);
    },
  },
};
</script>

<style scoped></style>

2.图示:

点击之后:

(5)实现数组的响应式方法

 1.数组中的push方法

<template>
  <div class="">
    <ul>
      <li v-for="(item, index) in arr" :key="index">{{ item }}</li>
      <hr />
      <button @click="fn">点击添加</button>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      arr: ["小红", "小明", "小华"],
    };
  },
  name: "",
  methods: {
    fn() {
      this.arr.push("小蔡");
    },
  },
};
</script>

<style scoped></style>

2.图示

3.使用上述的两种方法

(1)代码

<template>
  <div class="">
    <ul>
      <li v-for="(item, index) in arr" :key="index">{{ item }}</li>
      <hr />
      <button @click="fn">点击添加</button>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      arr: ["小红", "小明", "小华"],
    };
  },
  name: "",
  methods: {
    fn() {
      this.$set(this.arr, this.arr.length, "小蔡");
    },
  },
};
</script>
<style scoped></style>

(2)图示:

 

(3) this.$set(this.arr, this.arr.length, "小蔡");参数解析 |  与对象的对比   this.$set(this.obj, "c", 3);(可在上方对象的描述进行查找)

this.arr:数组                                                              this.obj:对象

this.arr.length:要添加的索引的位置                          "c":对象中的key值

"小蔡":要进行添加的值                                              3:对象中的value值

(4)使用Vue.set方法

1.代码:

<template>
  <div class="">
    <ul>
      <li v-for="(item, index) in arr" :key="index">{{ item }}</li>
      <hr />
      <button @click="fn">点击添加</button>
    </ul>
  </div>
</template>

<script>
import Vue from "vue";
export default {
  data() {
    return {
      arr: ["小红", "小明", "小华"],
    };
  },
  name: "",
  methods: {
    fn() {
      Vue.set(this.arr, this.arr.length, "小蔡");
    },
  },
};
</script>
<style scoped></style>

2.图示:

 3. 区别

1.引入了

import Vue from "vue";

2.而this.$set直接在原型链中进行查找

Logo

前往低代码交流专区

更多推荐