前端学习笔记-vue列表处理

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 动画 / 模糊缩略图)体验更好。
相关推荐
itmigrate21 小时前
前端项目里,Object.is 并不是 === 的平替
前端
学长毕设1 天前
基于SpringBoot的青少年编程学习平台系统-附源码
spring boot·学习·青少年编程
小大宇1 天前
Vue知识点6-computed计算属性
前端·javascript·vue.js
程序员海军1 天前
尤雨溪 : Vue 4 已经在规划中了!
前端·javascript·vue.js
2601_949970691 天前
HumanizeDuration 跨端三方库仓颉适配全流程
前端·javascript·flutter
风骏时光牛马1 天前
后端服务接口开发与性能优化
前端
kyriewen1 天前
我让 4 个 AI 互相 review 代码,最温柔的那个下手最狠
前端·程序员·ai编程
计算机魔术师1 天前
493家公司白砸AI钱?Apollo这组数据戳破了幻觉
前端
IT_陈寒1 天前
Java静态变量初始化坑得我头皮发麻
前端·人工智能·后端
柳杉1 天前
用 Codex 完成智慧高速 3D 可视化大屏,从 18 张行业设计稿到可交互的运行监测中心
前端·ai编程·数据可视化