Vue瀑布流长列表渲染卡顿,怎么优化?
最近在做图片瀑布流页面,用CSS Grid布局配合v-for渲染500条数据,滚动特别卡顿。试过把图片懒加载改成v-lazy,但滑动到中间位置就直接卡死不动了。
代码结构大概是这样写的:
<template>
<div class="grid" :style="{ '--cols': cols }">
<div
v-for="(item, index) in items"
:key="index"
class="grid-item"
:style="{ '--rowSpan': item.rowSpan }"
>
<img :src="item.url" @load="onImageLoad(index)">
</div>
</div>
</template>
<style>
.grid { display: grid; gap: 10px; grid-template-columns: repeat(var(--cols), 1fr); }
.grid-item { grid-row-end: span var(--rowSpan); }
</style>
试过用计算属性分段渲染,但计算图片实际高度时总出错,动态计算rowSpan的逻辑卡在布局重排上。有没有更好的实现方式或者需要调整的代码细节?
你现在的CSS Grid布局加v-for直接渲染500条,浏览器要做大量布局计算。再加上图片加载触发的onImageLoad频繁更新rowSpan,造成频繁重排重绘,性能扛不住很正常。
优化方向:
虚拟滚动必须上。只渲染当前可视区域+缓冲区域的图片,滚动时动态更新。推荐使用[Vue Virtual Scroller](https://github.com/Akryum/vue-virtual-scroller),开箱即用。
图片懒加载不要用v-lazy。原生的IntersectionObserver性能更好,比如这样:
动态计算rowSpan的问题。你需要等图片实际加载完成后再计算高度,不能直接在onImageLoad里改数据。建议在图片onload之后,用requestIdleCallback来处理布局更新。
CSS方面加点force硬件加速:
图片预加载和压缩也很关键。确保图片本身是webp格式,而且服务端做了响应式裁剪。
如果还是卡,可以考虑退而求其次用绝对定位模拟瀑布流,用js计算每个item的top/left。虽然麻烦,但比Grid布局在大数据量下更可控。
把这些都改完之后,我估计你500条数据也能顺畅滑动。我之前就是这么搞定的,卡顿问题基本消失。