vue数组和对象响应式杂谈

4,437 阅读2分钟

数组响应式

1. 基本理解

arr[i] = xxx和arr.length = len:这两种方式都不会立刻触发响应式

push pop shift unshift splice sort revcerse 或者直接给数组赋值等都会触发响应式
concat、filters、slice等等不对数组本身造成变化的都不会出发响应式
concat会返回新数组,不对原有数组操作

image.jpeg

// 示例1:
items: [
  { name: "a", age: 10 },
 { name: "b", age: 5 }
]
vm.items[0].age =20    // 会触发渲染
items: [1, 2]   vm.items[0]=99     // 不会触发渲染,但是值在内存中,如果有其他的渲染,那么这个内存的值会被一起渲染出去
vm.items.push(6)             // 99 2 6

2. 通过set实现数组下标响应式

// 方式1:
vm.$set(vm.items, indexOfItem, newValue)
//vm.$set(数组名字, 改变的索引位置, 需要更改的值)
//this.$set(arr,1,'我想要不要被改变')

// 方式2:
Vue.set(vm.items, indexOfItem, newValue)
//Vue.set(数组名字, 改变的索引位置, 需要更改的值)
// Vue.set(arr,1,'我想被改变')

对象响应式

1. 基本理解

Vue不能检测对象属性的添加、删除(仅此而已,可直接对该对象重新赋值、修改该对象或内层对象的属性)

也就是说已经有了一个对象,如果我们手动给对象增加属性,或者删除属性,那么vue检测不到变化。

// 示例1:
items: {
    name: "xiaomei",
    age: 18,
    habby: {}
}

vm.items.habby.a = 'AA'     // 不会触发重渲染, 但是值在内存中
vm.items.age = 20            // 触发重渲染,并且将habby.a在内存中的值也渲染了
// 删除age或者增加新属性都不会触发冲渲染

2. 通过set实现对象响应式

方法一:Vue.set(对象, 对象属性, 属性值)
方法二:this.$set(对象, 对象属性, 属性值)
eg:this.$set(item, 'taskList', [1,2,3])
item: {
  taskList: [1,2,3]
}

Vue.delete()&this.$delete()

一般我们删除对象某个属性,使用delete obj.xx,这种删除操作不会触发响应式,但是如果我们需要删除操作是响应式的,可以使用

Vue.delete(obj, 'key')
或者
this.$delete(obj, 'key')

遗漏点总结

<template>
  <div>
    <div>a: {{ a }}</div>
    <div @click="clickBtn">点我</div>
    <div>a: {{ a }}</div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      a: {
        b: 'bbbbb',
        c: {
          d: 'ddddd'
        }
      }
    }
  },
  methods: {
    clickBtn () {
      console.log('this.a前====>', this.a);
      // 对a整体赋值替换之后,a中的原有属性bcd仍然是响应式的,新加的e仍然是响应式的,因为
      // vue在data进行set赋值的时候,还会通过observe方法去判断这个新值是否是对象,而且
      // 是否已经有响应式初始化。如果没有,重新对其进行响应式初始化。这里e就是被重新响应式初始化的
      this.a = {
        b: 'xxxxx',
        c: {
          d: 'tttttt'
        },
        e: 'eeeeeee'
      }
      this.a.b = 'uuuuu'
      // 这种方式的新增对象属性h是不具有响应式的
      this.a.h = 'hhhhhh'
      // 对象实例的f属性并不属于data中,也不具有响应式;如果需要f成为响应式,除了$set之外,还必须将f变成data中的一个属性(挂载到data中的对象或者数组中)
      this.f = 'ffffff'

      console.log('this.a后====>', this.a);
      console.log('this前', this);
      // 这种方式给data中的a新增的g属性是具有响应式的。
      this.$set(this.a, 'g', 'gggggg')
      console.log('this后', this);
    }
  }
}
</script>

<style>
</style>





  1. 已经在data中对象/数组,如果想添加响应式属性时,可以采用$set的方式;如果这个变量本身就不在data中,那么是没有办法变成data中的响应式变量的。

  2. data中的对象/数组进行整体替换的时候,如果替换的新对象或者数组中多了属性,那么这个多的属性也是响应式的;因为vue在data进行set赋值的时候,还会通过observe方法去判断这个新值是否是对象,而且是否已经有响应式初始化。如果没有,重新对其进行响应式初始化

  3. 可以在控制台通过某个属性是否有set和get判断这个属性是否是响应式


写在后面

可以结合博主的另外一篇文章看,印象会更深刻