13 长列表 --- 用 Object.freeze / markRaw 禁用响应式
一句话理解
渲染 几千上万条只读数据 时,让 Vue 给每一条都建立响应式追踪是巨大浪费。用 Object.freeze(Vue 2)或 markRaw(Vue 3)禁止 Vue 劫持这些数据,初始化时间能大幅缩短。
为什么
假设有 1 万条数据,每条 5 个字段 = 5 万个属性。如果全部响应式,Vue 要为这 5 万个属性建立 getter/setter 和依赖收集------光初始化就要几百毫秒甚至卡顿。
而这些数据如果是只读展示(不修改、不双向绑定),完全可以跳过响应式。
代码示例
Vue 3:markRaw + 普通展示:
vue
<template>
<ul>
<li v-for="item in hugeList" :key="item.id">
{{ item.name }} - {{ item.email }}
</li>
</ul>
</template>
<script setup>
import { markRaw } from 'vue'
// 1 万条只读数据:markRaw 禁用响应式,初始化飞快
const hugeList = markRaw(
Array.from({ length: 10000 }, (_, i) => ({
id: i,
name: `用户${i}`,
email: `user${i}@x.com`,
}))
)
</script>
Vue 2:Object.freeze:
js
export default {
data() {
return {
// 冻结后 Vue 跳过响应式处理,1 万条数据秒渲染
hugeList: Object.freeze(fetchTenThousandItems()),
}
}
}
新人提示
- 适用前提:数据只读、不需要修改驱动视图。如果用户要编辑某行,这条数据就不能冻结。
- 如果列表既要大又要可滚动渲染,配合虚拟滚动(只渲染可视区域 DOM)才是终极方案。
- 别在数据需要响应式时强行 freeze,否则改了界面不更新,会很困惑。
14 图片按需加载(懒加载)
一句话理解
一个图片画廊页面有 100 张图,别一次性全加载------滚动到可视区域时再加载,首屏快、流量省。
为什么
图片是页面体积的大头。首屏只看得到几张图,却要下载全部 100 张,既慢又费流量。懒加载让图片"进入视野才下载"。
代码示例
方案一:原生 loading="lazy"(最简单,现代浏览器都支持):
vue
<template>
<!-- loading="lazy" 浏览器自动懒加载,零 JS -->
<img
v-for="img in images"
:key="img.id"
:src="img.url"
loading="lazy"
alt="图片"
/>
</template>
方案二:IntersectionObserver(更可控):
vue
<template>
<img
v-for="img in images"
:key="img.id"
:data-src="img.url" <!-- 先不设 src,避免立即加载 -->
ref="imgRefs"
alt="图片"
/>
</template>
<script setup>
import { onMounted, onBeforeUnmount } from 'vue'
import { ref } from 'vue'
const imgRefs = ref([])
let observer = null
onMounted(() => {
// 观察每张图片是否进入可视区域
observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target
img.src = img.dataset.src // 进入视野,才真正加载
observer.unobserve(img) // 加载后停止观察
}
})
})
imgRefs.value.forEach(img => observer.observe(img))
})
onBeforeUnmount(() => observer?.disconnect())
</script>
方案三:第三方指令 v-lazy(VueLazyload 等库):
vue
<template>
<img v-lazy="img.url" v-for="img in images" :key="img.id" />
</template>
新人提示
- 优先用原生
loading="lazy",简单够用。 - 头图、首屏关键图不要懒加载(反而拖慢 LCP 指标)。
- 配合占位图(loading 动画 / 模糊缩略图)体验更好。