news 2026/2/3 18:14:39

Vue 长列表卡顿、滚动掉帧怎么办?一次性讲清楚

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vue 长列表卡顿、滚动掉帧怎么办?一次性讲清楚

文章目录

    • 前言
    • Vue 长列表为什么一定会卡?
      • 1. v-for 渲染大量节点的真实代价
      • 2. DOM 数量过多,回流重绘是致命的
      • 3. 图文混排 + 复杂组件 = 雪上加霜
    • 核心解法:虚拟列表(Virtual List)
      • 1. 虚拟列表原理一句话版
      • 2. vue-virtual-scroller 快速上手 Demo
        • 安装
        • 基础示例(可直接跑)
        • 关键点解析
    • key 用不好,虚拟列表也救不了你
      • 错误示例
      • 正确示例
    • keep-alive 和组件卸载策略
      • keep-alive 的正确用法
      • 离开页面主动清理数据
    • IntersectionObserver 做懒加载
      • 图片懒加载示例
    • 实战结果:10 万级表格渲染
    • 总结

前言

在 Vue 项目里,只要一遇到长列表,很多同学第一反应都是:

“我这也没干啥啊,就是 v-for 渲染个列表,怎么就卡成 PPT 了?”

更狠一点的,产品一句话:

“这个页面数据有点多,可能十几万条吧。”

然后你就知道,这一页不优化是肯定过不去了。

这篇文章我们就从为什么卡开始,一步一步讲清楚Vue 长列表性能问题的本质,以及真正能落地的解决方案

Vue 长列表为什么一定会卡?

先说结论一句话版:

卡,不是 Vue 慢,是 DOM 太多。

1. v-for 渲染大量节点的真实代价

假设你写了这样一段代码:

<div v-for="item in list" :key="item.id"> {{ item.name }} </div>

如果list有 10 万条数据,意味着什么?

  • 浏览器里会真实创建10 万个 DOM 节点

  • 每次滚动都会涉及:

    • 布局计算(Layout)
    • 回流(Reflow)
    • 重绘(Repaint)
  • 任意一次父组件更新,都可能触发这些节点的 diff

这不是 Vue 的锅,这是浏览器物理极限的问题

2. DOM 数量过多,回流重绘是致命的

浏览器渲染流水线大概是:

JS → Style → Layout → Paint → Composite

当 DOM 数量过多时:

  • Layout 时间暴涨
  • Scroll 时频繁触发 repaint
  • FPS 掉到 30 以下,人眼就明显感觉卡

这也是为什么你会看到:

  • 滚动时页面发虚
  • 快速滑动直接“锁死”
  • 真机比模拟器还卡

3. 图文混排 + 复杂组件 = 雪上加霜

如果列表项里还有:

  • 图片
  • 自定义组件
  • 动态高度
  • hover / 动画

那每一行的渲染成本都会进一步放大。

所以,结论很清楚:

长列表,绝对不能一次性渲染完。

核心解法:虚拟列表(Virtual List)

虚拟列表的核心思想其实很简单:

只渲染“屏幕可见的那一小部分 DOM”,其他的用占位撑高度。

1. 虚拟列表原理一句话版

假设屏幕一次最多只能看到 20 行:

  • DOM 中永远只存在 20~30 行
  • 滚动时,复用 DOM 节点
  • 数据在变,DOM 不新增

这就是虚拟列表。


2. vue-virtual-scroller 快速上手 Demo

这是 Vue 里最成熟、最常用的方案之一。

安装
npminstallvue-virtual-scroller
基础示例(可直接跑)
<template> <RecycleScroller :items="list" :item-size="50" key-field="id" > <template #default="{ item }"> <div class="row"> {{ item.text }} </div> </template> </RecycleScroller> </template> <script setup> import { RecycleScroller } from 'vue-virtual-scroller' const list = Array.from({ length: 100000 }).map((_, i) => ({ id: i, text: `第 ${i} 行数据` })) </script>
关键点解析
  • item-size非常重要,最好是固定高度
  • key-field:告诉组件用哪个字段复用 DOM
  • 内部使用的是 DOM 复用,不是频繁创建/销毁

实测:10 万条数据,滚动依然 60 FPS。

key 用不好,虚拟列表也救不了你

很多列表性能问题,其实是key 用错了

错误示例

<div v-for="(item, index) in list" :key="index">

问题:

  • 数据插入 / 删除时
  • index 全部变化
  • Vue 会误以为所有节点都变了

正确示例

<div v-for="item in list" :key="item.id">

记住一句话:

key 一定要稳定、唯一、和业务语义一致。

keep-alive 和组件卸载策略

在分页列表或 Tab 场景中,经常会遇到:

“切换回来列表还在,但怎么感觉越来越卡?”

keep-alive 的正确用法

<keep-alive :max="2"> <router-view /> </keep-alive>
  • 控制缓存页面数量
  • 避免无限缓存导致内存膨胀

离开页面主动清理数据

onDeactivated(()=>{list.value=[]})

对于超大列表,离开页面就应该释放内存,不要心疼。

IntersectionObserver 做懒加载

对于图片、复杂组件,可以再加一层优化。

图片懒加载示例

constobserver=newIntersectionObserver(entries=>{entries.forEach(entry=>{if(entry.isIntersecting){entry.target.src=entry.target.dataset.src observer.unobserve(entry.target)}})})
  • 图片进入可视区才加载
  • 极大降低首屏压力

实战结果:10 万级表格渲染

优化前:

  • 首屏白屏 3~5 秒
  • 滚动 FPS < 30

优化后(虚拟列表 + 懒加载):

  • 首屏 < 500ms
  • 滚动稳定 60 FPS

总结

Vue 长列表优化,本质是“控制 DOM 数量”。
只要 DOM 在可控范围内,性能问题基本都能解决。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/3 1:12:24

网盘直链下载助手:解锁高速下载的实用技巧

还在为网盘下载速度慢而烦恼吗&#xff1f;这款免费开源的网盘直链下载助手将彻底改变你的下载体验&#xff01;它能够将六大主流网盘的分享链接一键转换为真实下载地址&#xff0c;让你无需安装任何客户端即可享受快速下载的便捷。 【免费下载链接】baiduyun 油猴脚本 - 一个免…

作者头像 李华
网站建设 2026/2/3 1:12:23

PlugY插件:暗黑破坏神2单机体验的革命性增强

PlugY插件&#xff1a;暗黑破坏神2单机体验的革命性增强 【免费下载链接】PlugY PlugY, The Survival Kit - Plug-in for Diablo II Lord of Destruction 项目地址: https://gitcode.com/gh_mirrors/pl/PlugY 当你在《暗黑破坏神II》的冒险旅程中因背包空间不足而被迫舍…

作者头像 李华
网站建设 2026/2/2 20:42:10

7个Maccy剪贴板管理器使用技巧:从新手到高手快速上手

7个Maccy剪贴板管理器使用技巧&#xff1a;从新手到高手快速上手 【免费下载链接】Maccy Lightweight clipboard manager for macOS 项目地址: https://gitcode.com/gh_mirrors/ma/Maccy Maccy是一款专为macOS设计的轻量级剪贴板历史管理工具&#xff0c;能够自动记录所…

作者头像 李华
网站建设 2026/2/2 7:37:58

GmsCore架构解构:从依赖注入到权限控制的逆向工程

问题的本质&#xff1a;为何需要重构Google服务框架&#xff1f; 【免费下载链接】GmsCore Free implementation of Play Services 项目地址: https://gitcode.com/GitHub_Trending/gm/GmsCore 当Android开发者试图摆脱Google生态的束缚时&#xff0c;一个根本性问题浮现…

作者头像 李华
网站建设 2026/2/2 15:44:38

D.二分查找-进阶——1385. 两个数组间的距离值

题目链接&#xff1a;1385. 两个数组间的距离值&#xff08;简单&#xff09; 算法原理&#xff1a; 大致思路与&#x1f447;相同&#xff0c;这题还稍微简单些 D.二分查找-进阶——2300. 咒语和药水的成功对数 解法&#xff1a;二分查找 对于arr1中的每一个元素x&#xff0c;…

作者头像 李华