为什么 Vue 更新所有组件而不是只更新 v-for 中更改的组件?
Why is Vue updating the all components instead of just the changed component in a v-for?
我有一个 v-for
列表,其中包含一个组件。在组件内部,我根据 属性 的值显示 <div>
或 <input>
。问题是,当我更改 属性 值时,v-for 中的所有项目都会更新,而不仅仅是更改的组件。这不是小型应用程序的问题,但我注意到在处理较大的数据集时性能会显着下降。
所以基本问题是:
如何避免只更新一个组件时渲染所有组件?
我都放在一个JSFiddle here里了。请注意,当您单击按钮以显示 C 组件输入时,所有组件都会重新呈现(显示在控制台中),而不仅仅是 C 组件。
HTML
<div id="app">
<button @click="showinput = 'C'">
Show C input
</button>
<br>
<br>
<div v-for="item in list" :key="item.id">
<list-item :item=item :showinput="showinput"></list-item>
</div>
</div>
<template id="list-item"> <span> <div v-if="showinput !== item.name">
{{item.name}}</div>
<input v-else
type="text"
v-model.lazy="item.name" >
</span>
</template>
JS
Vue.component('list-item', {
template: '#list-item',
props: ['item', 'showinput'],
data () {
return {
}},
beforeUpdate() {
console.log("Updating " + this.item.name)
}
});
// create a new Vue instance and mount it to our div element above with the id of app
var vm = new Vue({
el: '#app',
data: {
list: [{name: "A", id: 1}, {name: "B", id: 2}, {name: "C", id: 3},],
showinput: "X"
}
});
当您按下 "Show C" 按钮时,您正在更新 showInput
变量。现在这个 showInput
变量作为 prop 发送给你的 v-for
中的每个 <list-item />
并且通过这样做,你正在更新所有组件。
您的所有组件都使用相同的变量 showinput,因此所有组件都已更新。你最终只显示一个并不重要,vue 不知道这一点。实际上你还在渲染跨度,但它们只是空的。
你应该做的是过滤数据并在你的 v-for 中使用过滤后的数组。
computed: {
filteredList: function () {
return this.list.filter( item => item.name === this.showInput )
}
}
然后在你的 v-for
<div v-for=“item in filteredList” ...
乐
如果您想显示所有信息,但要更改显示方式,您可以将 list-item
组件拆分为 2 个组件,一个用于标签,一个用于输入。然后使用 :is to choose what template to use (or even a v-if
). I created this fiddle 来查看它的实际效果。请注意,onBeforeUpdate
不会再被调用,因为 vue 会重新创建组件。
这似乎在 vue 3 中可以修复,因为它将支持组件的部分渲染。
在您的组件 "list-item" 中,您有一个名为 "showinput" 的道具。
因此,每次更改此道具值时,您的组件都会更新。
现在,无论何时单击 "Show C input",都会更新 "showinput",并且当您将 "v-for" 用于 "list-item" 组件时,每个组件都附有 "showinput" "list-item" 因此所有组件都将更新。
我有一个 v-for
列表,其中包含一个组件。在组件内部,我根据 属性 的值显示 <div>
或 <input>
。问题是,当我更改 属性 值时,v-for 中的所有项目都会更新,而不仅仅是更改的组件。这不是小型应用程序的问题,但我注意到在处理较大的数据集时性能会显着下降。
所以基本问题是:
如何避免只更新一个组件时渲染所有组件?
我都放在一个JSFiddle here里了。请注意,当您单击按钮以显示 C 组件输入时,所有组件都会重新呈现(显示在控制台中),而不仅仅是 C 组件。
HTML
<div id="app">
<button @click="showinput = 'C'">
Show C input
</button>
<br>
<br>
<div v-for="item in list" :key="item.id">
<list-item :item=item :showinput="showinput"></list-item>
</div>
</div>
<template id="list-item"> <span> <div v-if="showinput !== item.name">
{{item.name}}</div>
<input v-else
type="text"
v-model.lazy="item.name" >
</span>
</template>
JS
Vue.component('list-item', {
template: '#list-item',
props: ['item', 'showinput'],
data () {
return {
}},
beforeUpdate() {
console.log("Updating " + this.item.name)
}
});
// create a new Vue instance and mount it to our div element above with the id of app
var vm = new Vue({
el: '#app',
data: {
list: [{name: "A", id: 1}, {name: "B", id: 2}, {name: "C", id: 3},],
showinput: "X"
}
});
当您按下 "Show C" 按钮时,您正在更新 showInput
变量。现在这个 showInput
变量作为 prop 发送给你的 v-for
中的每个 <list-item />
并且通过这样做,你正在更新所有组件。
您的所有组件都使用相同的变量 showinput,因此所有组件都已更新。你最终只显示一个并不重要,vue 不知道这一点。实际上你还在渲染跨度,但它们只是空的。
你应该做的是过滤数据并在你的 v-for 中使用过滤后的数组。
computed: {
filteredList: function () {
return this.list.filter( item => item.name === this.showInput )
}
}
然后在你的 v-for
<div v-for=“item in filteredList” ...
乐
如果您想显示所有信息,但要更改显示方式,您可以将 list-item
组件拆分为 2 个组件,一个用于标签,一个用于输入。然后使用 :is to choose what template to use (or even a v-if
). I created this fiddle 来查看它的实际效果。请注意,onBeforeUpdate
不会再被调用,因为 vue 会重新创建组件。
这似乎在 vue 3 中可以修复,因为它将支持组件的部分渲染。
在您的组件 "list-item" 中,您有一个名为 "showinput" 的道具。 因此,每次更改此道具值时,您的组件都会更新。
现在,无论何时单击 "Show C input",都会更新 "showinput",并且当您将 "v-for" 用于 "list-item" 组件时,每个组件都附有 "showinput" "list-item" 因此所有组件都将更新。