Vue学习记录07

列表渲染

v-for

可以使用v-for指令基于一个数组来渲染一个列表。v-for指令的值需要使用 item in items 形式的特殊语法,其中 items 是源数据的数组, 而 item 是迭代项的别名:

javascript 复制代码
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
html 复制代码
<li v-for="item in items">
  {{ item.message }}
</li>

在 v-for 块中可以完整地访问父作用域内地属性和变量。 v-for 也支持使用可选的第二个参数表示当前项的位置索引。

javascript 复制代码
const parentMessage = ref('Parent')
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
html 复制代码
<li v-for="(item, index) in items">
  {{ parentMessage }} - {{ index }} - {{ item.message }}
</li>

v -for 变量的作用域和下面的JavaScript代码很类似:

javascript 复制代码
const parentMessage = 'Parent'
const items = [
  /* ... */
]

items.forEach((item, index) => {
  // 可以访问外层的 `parentMessage`
  // 而 `item` 和 `index` 只在这个作用域可用
  console.log(parentMessage, item.message, index)
})

注意 v-for 是如何对应 forEach 回调的函数签名的。 实际上,也可以在定义 v-for 的变量别名时使用解构,类似:

html 复制代码
<li v-for="{ message } in items">
  {{ message }}
</li>

<!-- 有 index 索引时 -->
<li v-for="({ message }, index) in items">
  {{ message }} {{ index }}
</li>

对于多层嵌套的 v-for ,作用域的工作方式和函数的作用域很类似。每个 v-for 作用域都可以访问到父级作用域:

html 复制代码
<li v-for="item in items">
  <span v-for="childItem in item.children">
    {{ item.message }} {{ childItem }}
  </span>
</li>

也可以使用of作为分隔符来代替in,这更接近JavaScript的迭代器语法:

html 复制代码
<div v-for="item of items"></div>

v-for与对象

也可以使用v-for来遍历一个对象的所有属性。遍历的顺序会基于该对象调用Object.values()的返回值来决定。

javascript 复制代码
const myObject = reactive({
  title: 'How to do lists in Vue',
  author: 'Jane Doe',
  publishedAt: '2016-04-10'
})
html 复制代码
<ul>
  <li v-for="value in myObject">
    {{ value }}
  </li>
</ul>

可以通过提供第二个参数表示属性名(例如:key):

html 复制代码
<li v-for="(value, key) in myObject">
  {{ key }}: {{ value }}
</li>

第三个参数表示位置索引:

html 复制代码
<li v-for="(value, key, index) in myObject">
  {{ index }}. {{ key }}: {{ value }}
</li>

在 v-for 里使用范围值

v-for 可以直接接受一个整数值。在这种用例中,会将该模板基于1...n 的取值范围重复多次。

html 复制代码
<span v-for="n in 10">{{ n }}</span>

注意此处 n 的初值是从 1 开始而非 0。

<template> 上的 v-for

与模板上的 v-if 类似,也可以在<template>标签上使用 v-for 来渲染一个包含多个元素的块。例如:

html 复制代码
<ul>
  <template v-for="item in items">
    <li>{{ item.msg }}</li>
    <li class="divider" role="presentation"></li>
  </template>
</ul>

v-for 与 v-if

当它们同时存在于一个节点上时, v-if 比 v-for 的优先级更高。 这意味着 v-if 的条件将无法访问到 v-for 作用域内定义的变量别名:

javascript 复制代码
<!--
 这会抛出一个错误,因为属性 todo 此时
 没有在该实例上定义
-->
<li v-for="todo in todos" v-if="!todo.isComplete">
  {{ todo.name }}
</li>

在外先包装一层<template>再在其上使用 v-for 可以解决这个问题(这样也更加明显易读):

html 复制代码
<template v-for="todo in todos">
  <li v-if="!todo.isComplete">
    {{ todo.name }}
  </li>
</template>

通过key管理状态

Vue 默认按照"就地更新"的策略来更新通过 v-for 渲染的元素列表。当数据项的顺序改变时,Vue不会随之移动DOM元素的顺序,而是就地更新每个元素,确保它们在原本指定的索引位置上渲染。

默认模式是高效的,但只适用于列表渲染输出的结果不依赖子组件状态或者临时DOM状态(例如表单输入值)的情况。

为了给Vue一个提示,以便它可以跟踪每个节点的标识,从而重用和重新排序现有的元素,你需要为每个元素对应的块提供一个唯一的 key attribute:

html 复制代码
<div v-for="item in items" :key="item.id">
  <!-- 内容 -->
</div>

举例来说,为下列数组添加一个元素。

添加了一个王五,导致每个数组的index值发生变化,如果没有加key,所有数组是删除了后重新创建的。 如果加了:key,Vue是会保留原有数组的信息,而只添加一个数组,不会删除重建,提高了创建效率。

为什么一般绑定key不推荐index,而推荐id? 是由于如果在最开始为数组添加数据,每个数组的index值还是都会变化,数组还是会被销毁再创建。 而绑定一个静态值id,可以有效的使数据的对应关系不会轻易变化。

推荐 在任何可行的时候为 v-for 提供一个 key attribute,除非迭代的DOM内容非常简单(例如:不包含组件或有状态的DOM元素),或者你想有意采用默认行为来提高性能。

key 绑定的值期望是一个基础类型的值,例如字符串或者number类型。

数组变化侦测

变更方法

Vue 能够侦听响应式数组的变更方法,并在它们被调用时触发相关的更新。这些变更方法包括:

push() :向数组的末尾添加一个或多个元素。

javascript 复制代码
let arr = [1, 2, 3];  
arr.push(4); // arr 变为 [1, 2, 3, 4]

pop() :从数组的末尾移除一个元素。

javascript 复制代码
let arr = [1, 2, 3];  
let last = arr.pop(); // arr 变为 [1, 2], last 是 3

shift() : 从数组的开头移除一个元素。

javascript 复制代码
let arr = [1, 2, 3];  
let first = arr.shift(); // arr 变为 [2, 3], first 是 1

unshift() :向数组的开头添加一个或多个元素。

javascript 复制代码
let arr = [1, 2, 3];  
arr.unshift(0); // arr 变为 [0, 1, 2, 3]

splice() :从数组中添加或移除元素。

javascript 复制代码
let arr = [1, 2, 3];  
arr.splice(1, 1, 4, 5); // arr 变为 [1, 4, 5, 3]  
// 从索引1开始移除1个元素,并插入4和5

sort() : 对数组的元素进行排序,默认按字符串Unicode码点排序。

javascript 复制代码
let arr = [3, 1, 2];  
arr.sort(); // arr 变为 [1, 2, 3]

reverse() : 反转数组中元素的顺序。

javascript 复制代码
let arr = [1, 2, 3];  
arr.reverse(); // arr 变为 [3, 2, 1]

替换一个数组

变更方法,就是会对调用它们的原数组进行变更。相对地,也有一些不可变(immutable)方法,例如 filter(), concat() 和 slice(), 这些都不会更改原数组,而总是返回一个新数组。当遇到的是非变更方法时,我们需要将旧的数组替换为新的:

javascript 复制代码
// `items` 是一个数组的 ref
items.value = items.value.filter((item) => item.message.match(/Foo/))

你可能认为这将导致 Vue 丢弃现有的 DOM 并重新渲染整个列表------幸运的是,情况并非如此。Vue 实现了一些巧妙的方法来最大化对 DOM 元素的重用,因此用另一个包含部分重叠对象的数组来做替换,仍会是一种非常高效的操作。

展示过滤或排序后的结果

有时,我们希望显示数组经过过滤或排序后的内容,而不实际变更或重置原始数据。在这种情况下,你可以创建返回已过滤或已排序数组的计算属性。

例如:

javascript 复制代码
const numbers = ref([1, 2, 3, 4, 5, 6])

const evenNumbers = computed(() => {
  return numbers.value.filter((n) => n % 2 === 0)
})
html 复制代码
<li v-for="n in evenNumbers">{{ n }}</li>

在计算属性不可行的情况下(例如在多层嵌套的 v-for循环中),可以使用以下方法:

javascript 复制代码
const sets = ref([
  [1, 2, 3, 4, 5],
  [6, 7, 8, 9, 10]
])

function even(numbers) {
  return numbers.filter((number) => number % 2 === 0)
}
html 复制代码
<ul v-for="numbers in sets">
  <li v-for="n in even(numbers)">{{ n }}</li>
</ul>

在计算属性中使用 reverse() 和 sort() 的时候务必小心!这两个方法将变更原始数组,计算函数中不应该这么做。请在调用这些方法之前创建一个原数组的副本。

相关推荐
MarkHD4 小时前
智能体在车联网中的应用:第51天 模仿学习与离线强化学习:破解数据效率与安全困局的双刃剑
学习·安全
wearegogog1236 小时前
基于 MATLAB 的卡尔曼滤波器实现,用于消除噪声并估算信号
前端·算法·matlab
Drawing stars6 小时前
JAVA后端 前端 大模型应用 学习路线
java·前端·学习
崇山峻岭之间6 小时前
Matlab学习记录33
开发语言·学习·matlab
品克缤6 小时前
Element UI MessageBox 增加第三个按钮(DOM Hack 方案)
前端·javascript·vue.js
小二·7 小时前
Python Web 开发进阶实战:性能压测与调优 —— Locust + Prometheus + Grafana 构建高并发可观测系统
前端·python·prometheus
小沐°7 小时前
vue-设置不同环境的打包和运行
前端·javascript·vue.js
Irene19917 小时前
Vue3 <Suspense> 使用指南与注意事项
vue.js·suspense
科技林总7 小时前
【系统分析师】3.5 多处理机系统
学习
qq_419854057 小时前
CSS动效
前端·javascript·css