奥丁9
奥丁9
后端
数据库
redis
mysql
mongoDB
达梦
php
laravel
laravel-admin
dcat
表单
表格
java
spring
python
go
c
c++
前端
vue
nodejs
sass/less
html/css
前端框架
javascript
微信生态
公众号
小程序
uniapp
typescript
其他
AI
数据结构
安全
linux
seo
git
健身
算法
正则表达式
docker
待分类
前端
/
vue
vue数组双向绑定问题(数组更新检测、对象添加移除属性)
1年前
aoding9
45
前端
vue
原文链接:https://blog.csdn.net/qq_43812504/article/details/114626059 例子:三个列表数字首次渲染依次为100,200,300,点击对应的后面的按钮,要实现数字乘十,此时使用 this.arr[index]=this.arr[index]*10;进行更改的方式不起作用,改变了data中的arr数组,但是未能正确渲染到页面中。 ``` chatgpt的回答: 在Javascript中,修改数组下标是有效的,并且可以引起数组的变化。但是,在Vue的响应式系统中,直接修改数组下标是无法触发响应式更新的。 因为在Vue的响应式系统中,Vue使用了Object.defineProperty方法来监听数组的变化,而这个方法是无法监听到数组下标的变化的。也就是说,如果直接通过下标修改数组元素的值,不会触发Vue的响应式更新,导致界面不会发生对应的变化 ``` ```javascript <!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> ```  ### 解决方法一: ```javascript //参数一:要更改的原数组,参数二:索引,参数三:更改的值 aaa(item,index) { Vue.set(this.arr,index,item*10); } ``` ### 解决方法二:app.$set 只是 Vue.set 的别名。 ```javascript aaa(item,index) { this.$set(this.arr, index, item * 10); //app.$set(app.arr, index,item * 10); } ``` ### 解决方法三:使用数组方法 ```javascript 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()。它们不会变更原始数组,而总是返回一个新数组。当使用非变更方法时,可以用新数组替换旧数组: ```javascript 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 ```javascript 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.delete来删除对象中的某个属性 语法:this.delete(this.obj,'key') ``` this.$delete(this.someObject,'a') ```
本作品采用
《CC 协议》
,转载必须注明作者和本文链接