系列文章目录:
[Vue]目录
老师的课件笔记,不含视频 https://www.aliyundrive.com/s/B8sDe5u56BU笔记在线版: https://note.youdao.com/s/5vP46EPC
视频:尚硅谷Vue2.0+Vue3.0全套教程丨vuejs从入门到精通
文章目录
- 前言
- 1. 列表渲染
- 1.1 v-for
- 1.2 v-for 中的索引
- 2. v-for 遍历数组
- 3. v-for 遍历对象
- 4. v-for 遍历字符串
- 5. v-for 遍历指定次数
- 6. key的作用与原理
- 6.1 key
- 6.2 key错误演示
- 6.2.1 index作为key
- 6.2.2 不写key
- 6.2.3 出现错误的解释
- 6.3 可以对数组数据进行唯一标识的作为key
- 6.3.1 示例
- 6.3.2 解释
- 6.4 key的作用
- 6.5 用index作为key可能会引发的问题
- 6.6 开发中如何选择key
- 7. 列表过滤
- 7.1 监视属性实现
- 7.2 计算属性实现
- 8. 列表排序
vue 提供了 v-for 指令,用来辅助开发者基于数组、对象、字符串(用的很少)、指定次数(用的很少)等来循环渲染相似的 UI 结构。 v-for 指令需要使用item in items
或 item of items
的特殊语法,其中:
v-for 指令除了可以获取当前正在循环的项,还支持一个可选的第二个参数,即当前项的索引。语法格式为 (item, index) in items
或 (item, index) of items
。
v-for 指令中的 item 项和 index 索引都是形参,可以根据需要进行重命名。例如
(username, idx) in userlist
。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="root">
<ul>
<li v-for="(person, index) in persons">
[{{index}}] 姓名:{{person.name}} -- 年龄:{{person.age}}
li>
ul>
<ul>
<li v-for="(person, index) of persons">
[{{index}}] 姓名:{{person.name}} -- 年龄:{{person.age}}
li>
ul>
div>
body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const vm = new Vue({
el: '#root',
data: {
persons: [
{id: 101, name: 'ZS', age: 18},
{id: 102, name: 'LS', age: 19},
{id: 103, name: 'WW', age: 20}
]
}
})
script>
html>
使用 v-for 遍历对象,可以获取到三个参数,第一个参数为当前项的值,第二个参数为当前项对应的键,第三个参数为当前项的索引。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="root">
<ul>
<li v-for="(value, key, index) in zs">
{{index}} {{key}} : {{value}}
li>
ul>
div>
body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const vm = new Vue({
el: '#root',
data: {
persons: [
{id: 101, name: 'ZS', age: 18},
{id: 102, name: 'LS', age: 19},
{id: 103, name: 'WW', age: 20}
],
zs: {id: 101, name: 'ZS', age: 18}
}
})
script>
html>
使用 v-for 遍历字符串,可以获取到两个参数,第一个参数为当前正在遍历的字符,第二个参数为当前字符对应的索引或下标。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="root">
<ul>
<li v-for="(char, index) in my_str">
{{index}} -- {{char}}
li>
ul>
div>
body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const vm = new Vue({
el: '#root',
data: {
persons: [
{id: 101, name: 'ZS', age: 18},
{id: 102, name: 'LS', age: 19},
{id: 103, name: 'WW', age: 20}
],
zs: {id: 101, name: 'ZS', age: 18},
my_str: 'abcdefg'
}
})
script>
html>
使用 v-for 遍历指定次数,可以获取到两个参数,第一个参数为当前的数,第二个参数为当前的数对于的索引。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="root">
<ul>
<li v-for="(number, index) in 3">
{{index}} -- {{number}}
li>
ul>
div>
body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const vm = new Vue({
el: '#root',
data: {
persons: [
{id: 101, name: 'ZS', age: 18},
{id: 102, name: 'LS', age: 19},
{id: 103, name: 'WW', age: 20}
],
zs: {id: 101, name: 'ZS', age: 18},
my_str: 'abcdefg'
}
})
script>
html>
key 在 v-for 循环渲染中,可以为每个循环渲染出来的元素节点添加一个唯一的身份标识。
在使用 v-for 循环渲染时,最好写上 key
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="root">
<button @click="addPerson">添加button>
<ul>
<li v-for="(person, index) in persons" :key="index">
{{index}}: {{person.name}} -- {{person.age}}
<input type="text">
li>
ul>
div>
body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const vm = new Vue({
el: '#root',
data: {
persons: [
{id: 101, name: 'ZS', age: 18},
{id: 102, name: 'LS', age: 19},
{id: 103, name: 'WW', age: 20}
]
},
methods: {
addPerson() {
// 在数组的开头添加一人
this.persons.unshift({id: 104, name: 'TOM', age: 21})
}
},
})
script>
html>
通过观察上面的代码和运行结果,发现新的人员信息和新的输入框在添加到页面后出现了显示位置不匹配的问题。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="root">
<button @click="addPerson">添加button>
<ul>
<li v-for="(person, index) in persons">
{{index}}: {{person.name}} -- {{person.age}}
<input type="text">
li>
ul>
div>
body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const vm = new Vue({
el: '#root',
data: {
persons: [
{id: 101, name: 'ZS', age: 18},
{id: 102, name: 'LS', age: 19},
{id: 103, name: 'WW', age: 20}
]
},
methods: {
addPerson() {
this.persons.unshift({id: 104, name: 'TOM', age: 21})
}
},
})
script>
html>
通过观察,发现新的人员信息和新的输入框在添加到页面后依旧出现了显示位置不匹配的问题。
使用 v-for 进行循环渲染时,不写 key 时,vue 为自动为DOM元素设置一个 key ,key 的值为 index。即不写 key 与使用 index 作为 key 一样。
在提供的数据数组中,每个对象的 id 可以对该对象进行唯一标识,所以可以使用 id 作为key。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="root">
<button @click="addPerson">添加button>
<ul>
<li v-for="(person, index) in persons" :key="person.id">
{{index}}: {{person.name}} -- {{person.age}}
<input type="text">
li>
ul>
div>
body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const vm = new Vue({
el: '#root',
data: {
persons: [
{id: 101, name: 'ZS', age: 18},
{id: 102, name: 'LS', age: 19},
{id: 103, name: 'WW', age: 20}
]
},
methods: {
addPerson() {
this.persons.unshift({id: 104, name: 'TOM', age: 21})
}
},
})
script>
html>
提供观察结果发现,新的人员信息和新的输入框在加入页面显示后,没有出现不匹配的问题。
如果不对数据进行破坏顺序操作,则使用index作为key不会引发问题。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="root">
<button @click="addPerson">添加button>
<ul>
<li v-for="(person, index) in persons" :key="idnex">
{{index}}: {{person.name}} -- {{person.age}}
<input type="text">
li>
ul>
div>
body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const vm = new Vue({
el: '#root',
data: {
persons: [
{id: 101, name: 'ZS', age: 18},
{id: 102, name: 'LS', age: 19},
{id: 103, name: 'WW', age: 20}
]
},
methods: {
addPerson() {
this.persons.push({id: 104, name: 'TOM', age: 21})
}
},
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Documenttitle>
head>
<body>
<div id="root">
<input type="text" placeholder="请输入姓名..." v-model="keyWord" />
<ul>
<li v-for="(person, index) in filterPerson" :key="person.id">{{index}}: {{person.name}} -- {{person.age}} -- {{person.sex}}li>
ul>
div>
body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const vm = new Vue({
el: '#root',
data: {
// 保存用户的输入
keyWord: '',
persons: [
{ id: '001', name: '马冬梅', age: 19, sex: '女' },
{ id: '002', name: '周冬雨', age: 20, sex: '女' },
{ id: '003', name: '周杰伦', age: 21, sex: '男' },
{ id: '004', name: '温兆伦', age: 22, sex: '男' },
],
// 用于保存过滤后的数组
filterPerson: [],
},
watch: {
// 监视用户的输入
keyWord: {
// 初始化时立即执行一次,
// 初始用户没有输入,使用空字符串进行过滤,所有的数组元素都保留
// 显示数组中的全部元素
immediate: true,
handler(newVal) {
// 对数组进行过滤,并将过滤后的结果保存到filterPerson中
this.filterPerson = this.persons.filter((person) => {
// 查询姓名中是否包含用户输入的字符串
// 空字符串会返回0
// 包含输入的字符串则返回对应的索引
// 不包含返回-1
return person.name.indexOf(newVal) !== -1
})
},
},
},
})
script>
html>
计算属性与监视属性都能实现的功能,优先使用计算属性。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Documenttitle>
head>
<body>
<div id="root">
<input type="text" placeholder="请输入姓名..." v-model="keyWord" />
<ul>
<li v-for="(person, index) in filterPerson" :key="person.id">{{index}}: {{person.name}} -- {{person.age}} -- {{person.sex}}li>
ul>
div>
body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const vm = new Vue({
el: '#root',
data: {
// 保存用户的输入
keyWord: '',
persons: [
{ id: '001', name: '马冬梅', age: 19, sex: '女' },
{ id: '002', name: '周冬雨', age: 20, sex: '女' },
{ id: '003', name: '周杰伦', age: 21, sex: '男' },
{ id: '004', name: '温兆伦', age: 22, sex: '男' },
]
},
computed: {
// 由于页面中使用到了该计算属性,所以页面初始化时会调用一次
// 由于该计算属性使用了keyWord,所以当keyWord变化时,也会自动调用该计算属性
filterPerson() {
// 对数组进行过滤
return this.persons.filter((person)=>{
// 判断姓名是否包含用户的输入
return person.name.indexOf(this.keyWord) !== -1
})
}
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Documenttitle>
head>
<body>
<div id="root">
<input type="text" placeholder="请输入姓名..." v-model="keyWord" />
<button @click="sortType = 2">年龄升序button>
<button @click="sortType = 1">年龄降序button>
<button @click="sortType = 0">原顺序button>
<ul>
<li v-for="(person, index) in filterPerson" :key="person.id">{{index}}: {{person.name}} -- {{person.age}} -- {{person.sex}}li>
ul>
div>
body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const vm = new Vue({
el: '#root',
data: {
// 保存用户的输入
keyWord: '',
// 数据显示的顺序
// 默认为0(原顺序) 1降序 2升序
sortType: 0,
persons: [
{ id: '001', name: '马冬梅', age: 19, sex: '女' },
{ id: '002', name: '周冬雨', age: 20, sex: '女' },
{ id: '003', name: '周杰伦', age: 21, sex: '男' },
{ id: '004', name: '温兆伦', age: 22, sex: '男' },
],
},
computed: {
filterPerson() {
// 保存过滤后的数据
const personArr = this.persons.filter((person) => {
return person.name.indexOf(this.keyWord) !== -1
})
// 对过滤后的数据进行排序
// 如果需要的数组顺序不为原顺序,则进行排序
if (this.sortType) {
// 排序
personArr.sort((p1, p2) => {
// 判断是要降序还是升序
return this.sortType === 1 ? p2.age - p1.age : p1.age - p2.age
})
}
// 然后数组
return personArr
},
},
})
script>
html>