从入门到项目实战 - Vue 列表渲染

简介: 从入门到项目实战 - Vue 列表渲染


Vue 列表渲染



1. 列表渲染基础

1.1 什么是列表渲染

列表渲染是一种将一个数组、字符串、对象、数字以一定的方式展开成多个项目渲染到页面上的方式。

1.2 基本用法举例

1.2.1 数组

<ol>
  <li v-for="(item, index) in ['A', 'B', 'C']">item = {{ item }}, and index = {{ index }}</li>
</ol>

其渲染效果为:

注意:

  • 使用 v-for ... inv-for ... of 都可以,它们没有区别。(后文不在赘述)

1.2.2 数字

v-for 可以直接接受一个整数值,这相当于接受一个从 1 开始到该整数的数组。例如:

<ol>
  <li v-for="(number, index) in 3">number = {{number}}, and index = {{index}}</li>
</ol>

其渲染效果为:

注意:

  • index 和 所遍历项的数字在值上看,总是index比遍历项少1,因为 index 是从 0 开始计算而遍历项是从1开始算的。

1.2.3 字符串

v-for 指令可以遍历一个字符串。例如:

<ol>
  <li v-for="(item, index) of str">item = {{ item }}, and index = {{ index }}</li>
</ol>

其渲染效果为:

1.2.4 对象

v-for 指令在遍历一个对象时,将使用 JavaScript 对象的 属性名(键)作为遍历时的 index,使用 与该 属性名 对应的 作为遍历项,例如:

<ol>
  <li v-for="(item, index) of { J: 'ack', B: 'ush', A: 'lice' }">index = {{ index }}, and item = {{ item }}</li>
</ol>

其渲染效果为:

1.2.5 集合(Set)

集合(Set)是 ECMA Script 6 中定义的一个存储任何类型的唯一值的类型,它最常用于对一个数组进行去重。比如:

const s = new Set(["张三", "李四", "王五", "李四", "王五"])
console.log(s);
console.log([...s]);

Out[]:

{ "Set(3)": [ "张三", "李四", "王五" ] }
[ "张三", "李四", "王五" ]

使用 v-for 遍历一个集合的例子如下:

const s = new Set(["张三", "李四", "王五", "李四", "王五"])
<ol>
  <li v-for="(item, index) of s">item = {{ item }}, and index = {{ index }}</li>
</ol>

其渲染效果为:

1.2.6 映射(Map)

提示: 在编程语言中的 Map 含义不是地图,而是映射,这也是该单词最原始的含义。

映射(Map)是 ECMA Script 6 中定义的一个用于存储键值对的类型,任何值(对象或者基本类型)都可以作为一个键或一个值。虽映射像对象那样,具有键值对的使用形式,使用 v-for 遍历一个 映射 与遍历一个数组的不同之处在于,遍历映射时将以从 0 开始的整数索引值作为 index,使用 [key, word] 形式的数组作为遍历项。例如:

const m = new Map()
m.set('张', '三');
m.set('李', '四');
m.set('王', '五');
<ol>
  <li v-for="(item, index) of m">item = {{ item }}, and index = {{ index }}</li>
</ol>

其渲染效果为:

2. 数组渲染进阶

2.1 列表渲染中的 key 属性

2.1.1 key 属性于虚拟DOM 的更新规则

key 是 vue 中虚拟 DOM 所使用的对象标识,当数据发生变化时,Vue 会根据 新数据 生成 新的 虚拟 DOM,然后对从上到下从外到内从左到右对虚拟DOM进行扫描,对于某一个虚拟DOM,新的虚拟 DOM 与 旧的虚拟 DOM 进行差异比较。比较方式为:

  • 先比较新旧虚拟 DOM 的 key 属性:
  • 如果新的虚拟DOM中key 不存在与 旧的虚拟DOM中,则:
    将该新的虚拟 DOM 更新到内存做为新的虚拟DOM,同时渲染到页面为新的真实DOM。
  • 如果新的虚拟DOM的 key 属性值存在于 旧的虚拟DOM 中,则:从前到后比较该虚拟DOM的所有内容(子元素)。
  • 如果内容没变,则:直接使用旧的虚拟DOM。
  • 如果内容改变,则在内容改变处更新虚拟DOM,将将其渲染为新的真实DOM。
  • 对于内容的内容依次方式递归处理。

2.1.2 省略 key 时可能出现的问题

很多时候的确不写 key 属性也能实现我们需要的效果,比如:

const data = ["尔康", "尔泰", "紫薇", "小燕子"];
<ul>
  <li v-for="(item, index) in data">{{ item }}</li>
</ul>

虽然我们没有指定key属性,但是效果依然可以正常渲染:

然而

2.1.3 使用 index 作为 key 可能出现的问题

多数情况下我们的确可以直接使用 index 作为 v-for 遍历所需的 key 使用,例如给定一个三级手风琴目录数据如下:

const menu = [
  { title: "一级目录1", childern: [
      { title: "1-1" },
      { title: "1-2" },
    ]
  },
  { title: "一级目录2" },
  { title: "一级目录3", childern: [
      {
        title: "3-1", childern: [
          { title: "3-1-1" },
          { title: "3-1-2" },
        ]
      },
      { title: "3-2" },
    ]
  }
]

我们对数据逐层进行展开:

<ul>
  <li v-for="(menu1, index1) in menu" :key="index1">
    <p>{{ menu1.title }}</p>
    <ul v-if="menu1.childern">
      <li v-for="(menu2, index2) in menu1.childern" :key="index2">
        <p>{{ menu2.title }}</p>
        <ul v-if="menu2.childern">
          <li v-for="(menu3, index3) in menu2.childern" :key="index3">
            <p>{{ menu3.title }}</p>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

其渲染效果为:

在 2.1.1 节中我们知道

2.1.4 开发中如何选择 key

在上面,我们讨论了两种和虚拟DOM有关的问题:

  1. 若列表渲染中存在逆序增减项目等类似 破环原先渲染项顺序 的更新行为:
    将产生没有必要的真实DOM更新,降低页面渲染效率。
  2. 若列表渲染中,渲染项还包含了表单。在破环顺序的曾减项时:
    将导致表单错位等意外情形发生。

在 Vue 中,key 属性是用于给 vue 框架标识虚拟DOM用的。为了避免上述非预期情况的发生,我们应该 使用能够唯一标识每条数据的值作为数据项们的 key 属性值。通过这种方式:

  1. 对于逆序增减等破坏顺序的操作:
    由于 key 属性标明了各条数据的唯一标识,Vue 能够正确识别后面没有改动的DOM,不会对这些不需要改动的 虚拟DOM 对于更新渲染到 真实DOM。
  2. 对于不仅破坏顺序,而且存在表单的情形:
    由于Vue能够正确唯一识别每一条 虚拟DOM 项,一旦虚拟DOM变化,Vue不会去检查包含表单子项的改动。这些表单往往又是有状态的,即当用户在真实DOM的表单上改变了这些表单值时,虚拟DOM却不会改变,Vue也不会知道这些变动。
    通过人为地添加每项地唯一标识 key,Vue不再需要检查子项内容而错误更新,直接更新破坏顺序增减地整项,就避免了这种更新错乱地行为发生。

因此 找到能够唯一标识每条数据的值作为数据项们的 key 属性值 就成了提高渲染效率、避免更新错误地关键。那么采用什么作为列表渲染中数据项地 key 呢?

一般在实际开发中,合格地后端都需要给前端返回一个每条数据的唯一标识,这个标识往往能在 数据库 中唯一的确定该条数据,这样不论什么时候从后端请求跟新的新数据都能够唯一识别这条数据。比如,在一个标识用户信息的数据表中,昵称往往是重复的,用户id是唯一的,那么就可以使用用户id作为key。

2.2 避免同一个元素上与 v-if 联用

目录
相关文章
|
1天前
|
资源调度 JavaScript 前端开发
Vue Router 的使用方式是什么
【8月更文挑战第30天】Vue Router 的使用方式是什么
8 2
|
1天前
|
JavaScript 前端开发 测试技术
Vue.js开发者必看!Vue Test Utils携手端到端测试,打造无懈可击的应用体验,引领前端测试新风尚!
【8月更文挑战第30天】随着Vue.js的普及,构建可靠的Vue应用至关重要。测试不仅能确保应用质量,还能提升开发效率。Vue Test Utils作为官方测试库,方便进行单元测试,而结合端到端(E2E)测试,则能构建全面的测试体系,保障应用稳定性。本文将带你深入了解如何使用Vue Test Utils进行单元测试,通过具体示例展示如何测试组件行为;并通过Cypress进行E2E测试,确保整个应用流程的正确性。无论是单元测试还是E2E测试,都能显著提高Vue应用的质量,让你更加自信地交付高质量的应用。
|
1天前
|
JavaScript 前端开发 UED
服务器端渲染新浪潮:用Vue.js和Nuxt.js构建高性能Web应用
【8月更文挑战第30天】在现代Web开发中,提升应用性能和SEO友好性是前端开发者面临的挑战。服务器端渲染(SSR)能加快页面加载速度并改善搜索引擎优化。Vue.js结合Nuxt.js提供了一个高效框架来创建SSR应用。通过安装`create-nuxt-app`,可以轻松创建新的Nuxt.js项目,并利用其自动路由功能简化页面管理。Nuxt.js默认采用SSR模式,并支持通过`asyncData`方法预取数据,同时提供了静态站点生成和服务器端渲染的部署选项,显著提升用户体验。
|
1天前
|
JavaScript 前端开发 C++
【Vue.js的终极对决】服务端渲染VS客户端渲染:一场关乎速度与SEO的生死较量!
【8月更文挑战第30天】Vue.js 是一个流行的 JavaScript 框架,支持服务端渲染(SSR)和客户端渲染。SSR 在服务器生成完整 HTML,有利于 SEO 并缩短首屏加载时间,但增加服务器负担;客户端渲染则在浏览器生成页面,提升交互性,降低服务器负载。本文通过代码示例对比两者优劣,并提供选择指南,帮助开发者根据 SEO 需求、交互性需求及服务器资源等条件,选择合适的渲染方式,从而优化应用性能和用户体验。
|
1天前
|
JavaScript 前端开发 UED
揭秘Vue.js高效开发:Vue Router如何让单页面应用路由管理变得如此简单?
【8月更文挑战第30天】随着Web应用复杂性的增加,单页面应用(SPA)因出色的用户体验和高效的页面加载性能而备受青睐。Vue.js凭借简洁的语法和灵活的组件系统成为构建SPA的热门选择,其官方路由管理器Vue Router则简化了路由管理。本文通过实战示例介绍如何利用Vue Router实现高效的SPA路由管理,包括命名路由、动态路由及其核心优势。
|
4天前
|
存储 JavaScript 前端开发
Vue应用瘦身秘籍:揭秘Vuex如何重塑你的应用状态,让复杂变简单!🔥
【8月更文挑战第27天】在开发Vue应用时,随着应用规模的增长,组件间通信与状态共享问题日益复杂。Vuex作为Vue官方推荐的状态管理库,提供了集中式存储仓库来管理组件的共享状态,简化状态跟踪与组件通信。Vuex的核心概念包括state(存储状态数据)、mutations(同步修改state)和actions(处理异步操作)。通过一个购物车应用示例展示了如何定义state、mutations及actions,以及如何在Vue组件中使用这些状态管理功能。掌握Vuex有助于提高应用的健壮性和可维护性。
29 0
|
4天前
|
存储 JavaScript
解锁Vuex高级玩法:模块化与插件共舞,让你的Vue项目状态管理如虎添翼!
【8月更文挑战第27天】Vuex是一款专为Vue.js应用程序设计的状态管理模式及库,它通过集中管理组件状态来确保状态变更的可预测性。在大型应用中,采用模块化管理可以让代码结构更加清晰,同时利用插件增强功能。模块化管理允许将store拆分为包含各自state、mutations、actions和getters的独立模块。插件则能监听状态变化,实现诸如日志记录或数据持久化等功能。本文通过具体示例介绍了如何在Vuex中实现模块化管理和插件的高级应用。
15 1
|
2天前
|
JavaScript 开发者
[译] 监听第三方 Vue 组件的生命周期钩子
[译] 监听第三方 Vue 组件的生命周期钩子
|
2天前
|
JavaScript 前端开发
[译] 复用 Vue 组件的 6 层手段
[译] 复用 Vue 组件的 6 层手段
|
3天前
|
JavaScript 开发者
vue学习之响应式数据绑定
响应式数据绑定
11 0