字数 1212,阅读大约需 7 分钟
在Vue3项目里,长列表渲染是常见问题。比如展示几百甚至几千条数据时,页面容易卡顿,滚动不流畅。这篇文章全部告诉你,帮你优化长列表性能。
1. 虚拟列表
虚拟列表是优化长列表的常用手段。它的核心思路是只渲染当前视口中的内容,不渲染所有数据。这样DOM元素数量大大减少,页面性能自然提升。
Vue3生态里有现成的虚拟列表组件,比如vue-virtual-scroller。使用方法很简单:
首先安装依赖:
npm install vue-virtual-scroller
然后在组件中引入并使用:
<template>
<RecycleScroller
class="scroller"
:items="longList"
:item-size="50"
key-field="id"
>
<template v-slot="{ item }">
<div class="list-item">{{ item.content }}</div>
</template>
</RecycleScroller>
</template>
<script setup>
import { RecycleScroller } from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
const longList = Array.from({ length: 10000 }, (_, i) => ({
id: i,
content: `Item ${i}`
}))
</script>
<style scoped>
.scroller {
height: 500px;
overflow-y: auto;
}
.list-item {
height: 50px;
line-height: 50px;
border-bottom: 1px solid #eee;
}
</style>
这个组件会自动计算可视区域,只渲染需要的元素。即使列表有10000条数据,DOM数量也保持在几十左右。
2. 懒加载
懒加载是指当元素进入视口时才加载内容。对于长列表中的图片或复杂组件,懒加载能减少初始渲染时间。
Vue3中可以用vue3-lazyload插件实现图片懒加载:
安装插件:
npm install vue3-lazyload
在main.js中引入:
import { createApp } from 'vue'
import App from './App.vue'
import VueLazyload from 'vue3-lazyload'
createApp(App)
.use(VueLazyload, {
loading: '/loading.gif', // 加载中占位图
error: '/error.png' // 加载失败占位图
})
.mount('#app')
在组件中使用:
<template>
<div v-for="item in longList" :key="item.id" class="list-item">
<img v-lazy="item.imageUrl" alt="item image">
<p>{{ item.content }}</p>
</div>
</template>
这样图片只有滚动到可视区域时才会加载,减轻了页面初始加载的压力。
3. 减少不必要的响应式数据
Vue3的响应式系统很强大,但如果长列表中的数据不需要响应式,就不要让它变成响应式。比如一些静态数据,或者只需要展示不需要修改的数据。
可以用markRaw标记数据,避免Vue对其进行响应式处理:
import { markRaw } from 'vue'
const staticList = markRaw(Array.from({ length: 10000 }, (_, i) => ({
id: i,
content: `Static Item ${i}`
})))
这样Vue不会追踪这些数据的变化,减少了性能开销。
4. 优化列表项组件
列表项组件如果太复杂,也会影响整体性能。可以从以下几点优化:
-
• 拆分组件:把复杂的列表项拆分成更小的组件,减少单个组件的渲染压力。 -
• 避免不必要的渲染:用 v-once指令标记静态内容,让Vue只渲染一次:<template>
<div class="list-item">
<p v-once>{{ item.staticContent }}</p>
<p>{{ item.dynamicContent }}</p>
</div>
</template> -
• 优化事件监听:如果列表项有很多事件监听,可以用事件委托代替每个项单独绑定事件。
5. 使用分页加载
如果虚拟列表和懒加载都不适合,分页加载也是一个选择。把长列表分成多页,每次只加载一页数据。
实现分页加载很简单:
<template>
<div>
<div v-for="item in currentPageData" :key="item.id" class="list-item">
{{ item.content }}
</div>
<button @click="loadNextPage" v-if="hasMore">加载更多</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
const page = ref(1)
const pageSize = ref(20)
const total = ref(1000)
const listData = ref([])
const hasMore = ref(true)
const loadData = async () => {
// 模拟请求数据
const res = await fetch(`/api/list?page=${page.value}&pageSize=${pageSize.value}`)
const data = await res.json()
listData.value.push(...data.list)
page.value++
if (listData.value.length >= total.value) {
hasMore.value = false
}
}
const loadNextPage = () => {
loadData()
}
// 初始加载第一页
loadData()
</script>
分页加载可以控制每次渲染的数据量,避免一次性渲染太多内容。
6. 避免使用复杂的CSS选择器
复杂的CSS选择器会增加浏览器的渲染时间。在列表项中,尽量使用简单的类选择器,避免嵌套过深或使用后代选择器。
比如:
/* 不好的写法 */
.list-container .list-item .item-content p {
color: #333;
}
/* 好的写法 */
.item-content-text {
color: #333;
}
简单的CSS选择器能让浏览器更快地匹配元素,提升渲染性能。
7. 使用requestAnimationFrame处理滚动事件
如果需要监听滚动事件做一些操作,比如加载更多数据,尽量用requestAnimationFrame包裹,避免频繁触发:
const handleScroll = () => {
requestAnimationFrame(() => {
const scrollTop = document.documentElement.scrollTop
const clientHeight = document.documentElement.clientHeight
const scrollHeight = document.documentElement.scrollHeight
if (scrollTop + clientHeight >= scrollHeight - 100) {
loadNextPage()
}
})
}
window.addEventListener('scroll', handleScroll)
这样可以确保滚动事件的处理函数在浏览器下一次重绘前执行,避免卡顿。
以上这些方法,你可以根据项目的实际情况选择使用。
优化长列表性能,关键是减少DOM元素数量、减轻渲染压力、避免不必要的操作。
做好这些,就能让长列表滚动更流畅。
🚀专注前沿技术拆解 | 每日 9:00 更新
👇 关注 | 点赞 | 分享,我们共同进化
🔥 热门文章推荐:

