我在大型阵列上遇到v-for
的性能问题。
问题在于,每次更换过滤器时,v-for
都会重新生成所有过滤的行。我们通过对v-show
元素进行v-if
和v-for
的组合来解决此问题。效果很好,每次过滤数组时,我们可以节省约700毫秒的重新绘制时间。
这样做的缺点是transition-group
(香蕉)会消失
在下面的示例中,您可以通过过滤某些内容,然后清除过滤器来查看此操作。通过使用v-show
,这些元素从左上角开始进行怪异的过渡。这不是我所期望的。
new Vue({
el: "#app",
data() {
return {
filter: null,
people: [],
useVshow: true,
settings: {
opacityOnly: false
}
}
},
created() {
/* Irerelevant for issue - Just some fancy example code: */
let arr = [];
for (let i = 0; i < 500; ++i) {
arr.push({
id: i,
name: `person ${i}`,
age: i,
face: Math.floor(Math.random() * 9),
show: true
});
}
this.people = arr;
},
computed: {
filteredPeople: function() {
return this.filter ? this.people.filter(person => person.name.includes(this.filter)) : this.people
}
},
watch: {
filter() {
for (const i of this.people) {
i.show = this.filter ? i.name.includes(this.filter) : true;
}
}
}
})
.wrapper {
position: relative;
}
.card {
transition: all 800ms ease-in-out;
}
.opacity-only {
transition: opacity 800ms ease-in-out;
}
.list-leave-active {
position: absolute;
}
.list-enter,
.list-leave-to {
opacity: 0;
transform: translateY(30px);
}
.container {
max-width: 520px;
margin: 0 auto;
}
/* Irerelevant for issue - Just some fancy example code: */
input {
width: 150px;
}
.card {
display: flex;
align-items: center;
flex-wrap: wrap;
margin: 10px 0;
}
.card .info p {
margin: 5px 10px;
}
.card .info .name {
font-weight: 600;
color: #48484c;
}
.card .info .age {
font-size: 14px;
color: #656565;
}
.card .avatar {
height: 80px;
border-radius: 50%;
border: 5px solid #ddd;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<main id="app">
<div class="container">
<label for="filter">Filter by name:</label>
<input name="filter" v-model="filter"> Use v-show: <input type="checkbox" v-model="useVshow">
<br>Only trantition opacity: <input type="checkbox" v-model="settings.opacityOnly">
<transition-group name="list" tag="div" class="wrapper">
<template v-if="useVshow">
<div v-for="person in people" v-show="person.show" :key="person.id" class="card" :class="{'opacity-only': settings.opacityOnly}">
<img class="avatar" :src="`https://randomuser.me/api/portraits/lego/${person.face}.jpg`">
<div class="info">
<p class="name">{{person.name}}</p>
<p class="age">{{person.age}} years old</p>
</div>
</div>
</template>
<template v-else>
<div v-for="person in filteredPeople" :key="person.id" class="card">
<img class="avatar" :src="`https://randomuser.me/api/portraits/lego/${person.face}.jpg`">
<div class="info">
<p class="name">{{person.name}}</p>
<p class="age">{{person.age}} years old</p>
</div>
</div>
</template>
</transition-group>
</div>
</main>
为什么会发生这种情况,并且有什么方法可以使返回转换与没有v-show
的情况一样?
EDIT:
添加了选项,仅用于@Sitethief指出的过渡不透明度
答案 0 :(得分:0)
我认为问题在于transition: all
对所有CSS属性都应用了过渡。其中包括position: absolute;
,如果您在切换滤镜时在开发人员中进行检查,则可以实时看到它。如果您将转换更改为transition: opacity 800ms ease-in-out;
之类的内容,列表项将不会在左上角开始。