vue数组双向绑定问题(数组更新检测、对象添加移除属性)

例子:三个列表数字首次渲染依次为100,200,300,点击对应的后面的按钮,要实现数字乘十,此时使用 this.arr[index]=this.arr[index]*10;进行更改的方式不起作用,改变了data中的arr数组,但是未能正确渲染到页面中。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <div v-for="(item,index) in arr">
            {{item}}
            <button @click='aaa(item,index)'>点击数字改变</button>
        </div>
    </div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        data: {
            arr:[
                100,
                200,
                300
            ]
        },
        methods: {
            aaa(item,index) {
                console.log('进入aaa里面了')
                console.log(item)
                console.log(index)
                this.arr[index]=this.arr[index]*10;//不能使用
                console.log(this.arr)
            }
            
        }
    })
</script>

</html>


在这里插入图片描述
解决方法一:

//参数一:要更改的原数组,参数二:索引,参数三:更改的值
         aaa(item,index) {
               Vue.set(this.arr,index,item*10);
        }

解决方法二:app.$set 只是 Vue.set 的别名。

         aaa(item,index) {
                 this.$set(this.arr, index, item * 10);
                 //app.$set(app.arr, index,item * 10);
        }

解决方法三:使用数组方法

         aaa(item,index) {
             this.arr.splice(index,1,item*10)
        }

重点:
Vue 将被侦听的数组的变更方法(7个)进行了包裹,所以它们也将会触发视图更新。在对数组进行处理时,可以选用这些方法来实现响应式。这些被包裹过的方法包括:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()
push() 向数组的后面添加元素,返回值:数组的新长度  arr.push(4,5)
pop()  从数组的尾部删除一个元素,返回删除的元素  arr.pop() 不用传参
unshift() 向数组的前面添加元素,返回值:数组的新长度  arr.unshift(0,1)
shift() 从数组头部删除一个元素,返回删除的元素  arr.shift() 不用传参
splice() :
	删除:两个参数,splice(index,num) 删除的第一项的位置以及要删除的项数
	添加:三个参数,插入起始位置、删除的项数(为0)、插入的项,向指定位置插入任意数量的项。arr.splice(1,0,"or","ue")
	替换:先删除再添加,三个参数:起始位置、删除的项数、要添加的项数。添加的与删除的数量不一定要一致。arr.splice(1,2,"or","ue")
sort():对数组元素进行排序,默认根据字符串Unicode码进行排序,对数字进行排序时参数要传递一个比较函数。
	sortNumber(a,b){
	      return a-b
	}reverse():该方法用于颠倒数组中元素的顺序

上述方法会变更调用了这些方法的原始数组。相比之下,也有非变更方法,例如 filter()、concat() 和 slice()。它们不会变更原始数组,而总是返回一个新数组。当使用非变更方法时,可以用新数组替换旧数组:

example1.items = example1.items.filter(function (item) {
  return item.message.match(/Foo/)
})

是用新数组替换旧数组不会导致 Vue 丢弃现有 DOM 并重新渲染整个列表,Vue 为了使得 DOM 元素得到最大范围的重用而实现了一些智能的启发式方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作

知识点:(官方文档)

由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。但我们要采取一些办法回避这些限制并保证它们的响应性。

对于数组:

Vue 不能检测以下数组的变动:

  • 当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
  • 当你修改数组的长度时,例如:vm.items.length = newLength
var vm = new Vue({
  data: {
    items: ['a', 'b', 'c']
  }
})
vm.items[1] = 'x' // 不是响应性的
vm.items.length = 2 // 不是响应性的

解决利用索引设置数组项的问题:

// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
//使用 vm.$set 实例方法,该方法是全局方法 Vue.set 的一个别名:
vm.$set(vm.items, indexOfItem, newValue)

解决修改长度:

vm.items.splice(newLength)





对于对象:

Vue 无法检测 property 的添加或移除。由于 Vue 会在初始化实例时对 property 执行 getter/setter 转化,所以 property 必须在 data 对象上存在才能让 Vue 将它转换为响应式的。例如:

var vm = new Vue({
  data:{
    a:1
  }
})
// `vm.a` 是响应式的
vm.b = 2
// `vm.b` 是非响应式的

对象的property添加:
使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式 property。

Vue.set(vm.someObject, 'b', 2)

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

this.$set(this.someObject,'b',2)

已有对象赋值多个新 property,在这种情况下,应该用原对象与要混合进去的对象的 property 一起创建一个新的对象。

// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })

对象property移除:
通过this. d e l e t e 来 删 除 对 象 中 的 某 个 属 性 : 语 法 : t h i s . delete来删除对象中的某个属性:语法:this. deletethis.delete(this.obj,‘key‘)

this.$delete(this.someObject,'a')