你是不是遇到过这样的问题:
-
一个页面加载了上千条数据,浏览器直接卡死
-
无限滚动页面,滑到底部几秒都没反应
-
切换 Tab 页组件太重,导致页面瞬间卡顿
这不是网络的问题,是你的“渲染策略太耿直了”。
本篇文章带你掌握三个核心手段:
虚拟滚动、分段渲染、延迟挂载,让页面“看起来啥都有,其实啥都没渲染”。
一、为什么渲染会“卡死浏览器”?
浏览器渲染是 CPU 密集型任务:
-
渲染 1000 条 DOM ≠ 快一点,是直接把你主线程“烧了”
-
React/Vue 等框架再牛,也架不住你同时渲染几百个复杂组件
所以我们要学会——藏起来、分批来、晚点再说
二、虚拟滚动:看起来很多,其实只渲染“正在看”的
场景:
-
长列表(聊天、评论、文件列表)
-
表格(10W 行 + 筛选)
原理:
“只渲染可视区域的元素,其余的用空占位撑起滚动高度”
<div class="scroll-container" @scroll="onScroll">
<div style="height: TOTAL_HEIGHT">
<div
v-for="item in visibleItems"
:key="item.id"
:style="{ transform: `translateY(${item.top}px)` }"
>
{{ item.text }}
</div>
</div>
</div>
常用库:
-
React:react-window, react-virtualized
-
Vue:vue-virtual-scroller, vite-plugin-virtual-list
提示:
-
尽量保证每项高度一致,或者提前计算高度
-
虚拟滚动不适合分页接口(适合一次拉全或本地数据)
三、分段渲染:慢慢来,不急
场景:
-
DOM 节点过多,一次挂载浏览器直接卡
-
数据量中等(300~1000 条)
方法:
把列表按批次切块渲染,每帧或每段时间补一部分
const chunkRender = (items, chunkSize) => {
let index = 0;
const renderNext = () => {
const slice = items.slice(index, index + chunkSize);
render(slice);
index += chunkSize;
if (index < items.length) {
requestAnimationFrame(renderNext);
}
};
renderNext();
};
好处:
-
没那么高级,但兼容性强、实现简单
-
结合 loading 状态让用户有节奏感
四、延迟挂载(lazy mount):用户没看到就别加载
场景:
-
多个 tab 页面组件结构复杂,切换卡顿
-
展开折叠的列表项中嵌套大量组件
方法:
“不展示就不挂载”、“展示再加载”
Vue 示例:
<TabPanel v-if="activeTab === 'chart'">
<HeavyChart />
</TabPanel>
或配合动态 import:
<Suspense>
<LazyTabComponent />
</Suspense>
注意:
-
延迟挂载 ≠ 懒加载数据,要搭配缓存/keep-alive 做好体验
五、这些优化不只是“提升帧率”,更是“防止系统爆炸”
性能问题往往不是“慢一点”,而是“彻底卡死”。
引发副作用包括:
-
卡顿 → 用户重复点击 → 接口多发 → 数据错乱
-
页面卡住 → 用户误以为出错 → 提高跳出率
-
主线程被锁 → UI 无响应 → 渲染不完整或动画中断
总结:让渲染“聪明一点”
现代前端不缺渲染能力,缺的是:
-
只做该做的事(虚拟滚动)
-
一步一步来(分段渲染)
-
没必要就别管(延迟挂载)
渲染不在多,而在刚好。
合理设计每一个 UI 组件的“上场时机”,
你会发现页面不光不卡,甚至更顺滑、更聪明、更有节奏感。