Appearance
列表渲染
v-for
html
<li v-for="item in items">{{ item.message }}</li>
<li v-for="(item, index) in items">{{ parentMessage }} - {{ index }} - {{ item.message }}</li>在 v-for 块中可以完整地访问父作用域内的属性和变量。v-for 也支持使用可选的第二个参数表示当前项的位置索引。
javascript
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])v-for变量的作用域类似于这段代码
javascript
const parentMessage = 'Parent'
const items = [
/* ... */
]
items.forEach((item, index) => {
// 可以访问外层的 `parentMessage`
// 而 `item` 和 `index` 只在这个作用域可用
console.log(parentMessage, item.message, index)
})也可以在定义v-for的变量别名时使用结构 :
html
<li v-for="{ message } in items">{{ message }}</li>
<!-- 有 index 索引时 -->
<li v-for="({ message }, index) in items">{{ message }} {{ index }}</li>多层嵌套的v-for作用域参考下面代码
javascript
<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">{{ item }}</div>v-for与对象
可以使用v-for来遍历对象.遍历的数序基于对该对象调用Object.value的返回值来决定
html
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
<ul>
<li v-for="(value, key) in myObject">{{ key }}: {{ value }}</li>
</ul>第三个参数表示索引位置
html
<ul>
<li v-for="(value, key, index) in myObject">{{ index }}. {{ key }}: {{ value }}</li>
</ul>在v-for里使用范围值
html
<div v-for="n in 10">{{ n }}</div>需要注意,这里n的值是从1开始的,而不是0
template上的v-for
v-for可以放在template上,这样可以避免渲染多余的元素
html
<ul>
<template v-for="item in items">
<li>{{ item.text }}</li>
</template>
</ul>v-for与v-if
当用在同一个节点上时,v-if比v-for优先级高,这意味着v-if将不包含在v-for的循环中,且v-if的条件无法访问到v-for作用域中的变量
html
<!--
这会抛出一个错误,因为属性 todo 此时
没有在该实例上定义
-->
<li v-for="todo in todos" v-if="!todo.isComplete">{{ todo.name }}</li>这个设定在Vue2中是不同的,v-for的优先级更高,为了避免混乱,建议使用template来包裹v-if条件
html
<template v-for="todo in todos">
<li v-if="!todo.isComplete">{{ todo.name }}</li>
</template>v-for与key
Vue默认使用"就地更新"的策略来处理列表渲染 :
1.不移动DOM元素
- 当数组顺序变化时,,不会根据数据的变化来移动
DOM元素 - 例如原数组为
[1, 2, 3],如果变为[2, 1, 3],则不会移动DOM元素,而是就地更新元素内容
2.就地更新DOM元素内容
Vue会对比数据变化,但是只会更新每个位置上元素的内容- 在上例中,原本显示A的位置现在会更新显示B的内容,原本B的位置显示A的内容
3.保留DOM状态
- 保留
DOM状态,如input输入框中的输入内容,textarea中的文本内容,select中的选中状态等
默认模式是高俏的,但只适用于列表渲染输出的结果不依赖子组件状态或者临时DOM状态(例如表单输入值)的情况只有在纯数据展示的情况下才key才可以省略 不进行任何交互,不涉及任何其他数据的状态.但是建议在使用时默认都加上key养成习惯
key的作用是给Vue提供一个唯一的标识符,以便在数据变化时,可以更高效地更新DOM元素,在设置key的时候需要保证key的唯一性
html
<ul>
<li v-for="item in items" :key="item.id">{{ item.text }}</li>
</ul>key的绑定至期望是一个基础类型的值,不要使用对象作为`key
组件上使用v-for
html
<MyComponent v-for="item in items" :key="item.id" />如果需要将迭代的数据传递给组件 :
html
<MyComponent v-for="item in items" :item="item" :key="item.id" />数组变化侦测
变更方法
Vue会自动侦测数组的变更方法,并在他们被调用的时候出发相关的更新,这些方法包括 :
push()pop()shift()unshift()splice()sort()reverse()
之外的方法不会被Vue侦测到,例如直接通过索引来修改数组
变异方法
这些方法会变更调用的原数组
javascript
items.push({ message: 'Baz' })非变异方法
这些方法不会变更调用的原数组,而是返回一个新的数组
- filter() - 过滤数组
- concat() - 合并数组
- slice() - 截取数组
- map() - 映射新数组
- flat()/flatMap() - 扁平化数组
使用这些方法时需要将旧数组替换为返回的新数组来触发更新
展示过滤或排序过后的结果
javascript
const numbers = ref([1, 2, 3, 4, 5])
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>TIP 之前提到过有些方法会改变数组的元数据,在计算属性中使用这些方法的时候务必小心,要保证计算属性中不应该有其他影响的原则 :
javascript
// 错误用法
return numbers.reverse()
// 正确用法
return [...numbers].reverse()