VUE中v-for更新检测
Posted 25氪
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VUE中v-for更新检测相关的知识,希望对你有一定的参考价值。
口诀:
- 数组变更方法,就会导致 v-for 更新,页面更新
- 数组非变更方法:返回新数组,就不会导致 v-for 更新,更新值检测不到可采用覆盖或者 this.$set()
数组变更方法如下:
1. arr.push()从后面添加元素
arr.push(5)
2. arr.pop()从后面删除元素,只能是一个
arr.pop()
3. arr.shift()从前面删除元素,只能删除一个
arr.shift()
4. arr.unshift()从前面添加元素,返回值时添加完后数组长度
arr.unshift(8)
5. arr.splice(i,n)删除从 i (索引值)开始之后删除的 N(删除的个数)个数
let arr = [1,2,3,4,5]
console.log(arr.splice(2,2)) //[3,4]
console.log(arr) // [1,2,5]
6. arr.sort()将数组进行排序,返回值排好的数组
let arr = [2,10,6,1,4,22,3]
console.log(arr.sort()) // [1, 10, 2, 22, 3, 4, 6]
let arr1 = arr.sort((a, b) =>a - b)
console.log(arr1) // [1, 2, 3, 4, 6, 10, 22]
let arr2 = arr.sort((a, b) =>b-a)
console.log(arr2) // [22, 10, 6, 4, 3, 2, 1]
7. arr.reverse() 将数组反转
let arr = [1,2,3,4,5]
console.log(arr.reverse()) // [5,4,3,2,1]
console.log(arr) // [5,4,3,2,1]
数组非变更方法如下:
1. arr.concat()连接两个数组
let arr = [1,2,3,4,5]
console.log(arr.concat([1,2])) // [1,2,3,4,5,1,2]
console.log(arr) // [1,2,3,4,5]
2. arr.slice(start,end)切去索引 start 到 end 索引值,不包含 start 索引值
let arr = [1,2,3,4,5]
console.log(arr.slice(1,3)) // [2,3]
覆盖方法
<li v-for="(val, index) in arr" :key="index">
{{ val }}
</li>
<button @click="sliceBtn">截取前3个</button>
sliceBtn(){
// 2. 数组slice方法不会造成v-for更新
// slice不会改变原始数组
// this.arr.slice(0, 3)
// 解决v-for更新 - 覆盖原始数组
let newArr = this.arr.slice(0, 3)
this.arr = newArr
},
this.$set()方法
<li v-for="(val, index) in arr" :key="index">
{{ val }}
</li>
<button @click="sliceBtn">更新下标0的值</button>
sliceBtn(){
// 更新某个值时,v-for是检测不到的
// this.arr[0] = 1000
// 解决- this.$set()
// 参数1:更新目标结构
// 参数2:更新位置
// 参数3:更新值
let newArr = this.arr.slice(0, 3)
this.arr = newArr
},
Vue:如何在 v-for 中执行响应式对象更改检测?
【中文标题】Vue:如何在 v-for 中执行响应式对象更改检测?【英文标题】:Vue: How to perform reactive object change detection in v-for? 【发布时间】:2019-05-02 13:59:06 【问题描述】:我阅读了this 文档,但无法使用建议的解决方案。
我有一个v-for
循环对象。这些对象随时间动态变化,我需要这种变化在 v-for 循环中反应性地显示。
<b-row lg="12" v-for="data in objects" :key="data.id">
<div v-if="data.loading">
loading...
data.loading
</div>
<div v-else>
loaded, done
data.loading
</div>
</b-row>
在我的方法中,我有一个 for 循环,它为每个对象下载数据并像这样更改对象值:
for(var i = 0; i<response.ids.length; i++)
var newId = response.ids[i].id
this.objects.newId = "loading":true, "id": newId
downloadSomething(newId).then(res =>
this.objects.newId = res[0] //<-- this change needs to be shown reactively.
)
根据 Vue 文档,对象更改不是反应性的:
var vm = new Vue(
data:
a: 1
)
// `vm.a` is now reactive
vm.b = 2
// `vm.b` is NOT reactive
Vue 提出了一些这样的解决方法:
Vue.set(vm.userProfile, 'age', 27)
更新
但对我来说,这只是在对象中创建一个具有相同 ID 的新参数,并创建重复键警告和其他问题。
我也在 Vue.set 之前尝试了Vue.delete
,但它实际上并没有删除。
有没有办法不替换键/值对,而是向 ID 为 newID
的根的第一个子节点添加更多/更改参数
谢谢!
【问题讨论】:
【参考方案1】:解决方案:将this.objects.newId = res[0]
替换为this.$set(this.objects, 'newId', res[0])
,它应该可以工作。
解释: this.$set
只是 Vue.set
的别名,可在任何 Vue 实例中使用。请记住,示例中的vm
(代表视图模型)与this
相同,相当于Vue 组件实例。同样由于 ES5 JS 的限制,您必须通过 Vue.set/this.$set
显式设置对象的属性才能手动触发重新渲染。这个问题会在 Vue 3.0 发布后解决。
希望这会有所帮助,如果您需要任何说明,请随时提问。
【讨论】:
我没有明确提到我的“对象”是一个对象而不是数组。 Vue.set/vm.$set 在 'objects' 中创建一个具有相同 ID 的新参数,并且不会替换现有参数。这会产生重复键警告和其他问题。我也在 Vue.set 之前尝试了 Vue.delete,但 Vue.delete 不起作用。 想通了。我在没有 Vue.set 的情况下为子对象设置初始键值,然后期望它随着 Vue.set 改变。事实证明,还需要使用 Vue.set 设置初始值(加载值)。我还有助于提高可读性。【参考方案2】:
当您想为现有对象(而不是直接定义数据)定义 新属性 时,您需要Vue.set()
,并且此函数会将新属性分配给内置观察程序,它会也变得被动。
这一切都在文档中进行了解释:https://vuejs.org/v2/guide/reactivity.html
在你的情况下,这似乎是你让它工作所需要的。在我的示例中:https://jsfiddle.net/efrat19/eywraw8t/484131/ 一个异步函数获取数据并定义一个新属性以包含响应。
new Vue(
el: "#app",
data:
objects:
property1:12
,
methods:
fetchDataAndAddProperty(response)
fetch('https://free.currencyconverterapi.com/api/v6/countries').then(res =>
res.json()).then(data => Vue.set(this.objects,'property2',data))
)
和模板:
<div id="app">
<div lg="12" v-for="(val,key,index) in objects" :key="index">
key:val
</div>
<button @click="fetchDataAndAddProperty()">fetch</button>
</div>
正如您在小提琴中看到的那样,新属性变为反应性并被显示。
【讨论】:
【参考方案3】:试试看:
downloadSomething(newId).then(res =>
this.$set(this.objects, 'newId', res[0])
)
【讨论】:
以上是关于VUE中v-for更新检测的主要内容,如果未能解决你的问题,请参考以下文章
在 bootstrap-vue datepicker 中检测 v-for 中每个元素的目标