列表渲染
基于人员列表案例遍历数组
v-for基于一个数组来渲染一个列表,使用形参p来遍历persons数组中的数据(像js中的for-in遍历) 可以使用:key动态绑定index索引值
记录本次学习过程中的第一个bug
代码和debug console的截图如下
消除bug
<li v-for="p in persons" :key="p.id">{{p.name}}-{{p.age}}</li>
在persons中接收多个元素 (a,b)in persons,也可以用of代替in
基于汽车案例遍历对象
html
<h2>做梦素材</h2>
<ul>
<li v-for="(value,key) in car" :key="key">
{{key}}-{{value}}
</li>
</ul>
script
car: {
name: '玛莎拉蒂',
price: '200w',
color: 'gold'
}
运行结果
遍历字符串
在data数据中添加字符串str:'hello',按照之前遍历对象的方式来遍历字符串 得到的运行结果截图如下
<!-- 遍历字符串 -->
<h2>测试遍历字符串</h2>
<ul>
<li v-for="(char,index) of str" :key="index">
{{key}}-{{value}}
</li>
</ul>
将index用作key不太合适,因为……(不涉及更新列表此时忽略不合适) 此处无太大功能暂时这样了
遍历指定次数(不常见)
遍历指定次数不需要对象数组等的数据,可以直接遍历一个数字
<li v-for="(a,b) of 5">
{{a}}-{{b}}
</li>
运行结果截图
所以a是数字值,b是索引值。
总结
v-for指令
- 用于展示列表数据
- 语法: v-for="(item,index) in xxx" :key="yyy"
- 可遍历:数组,对象,字符串(用的很少)、指定次数(用的很少)
key的原理
key可以对节点进行标识,相当于人类的身份证号。 在上述基于人员列表遍历数组的代码案例中,如果没有key列表的展示不会受到影响
需求:添加一个人在persons的数据的最前面,(真实项目开发中id不是前端人员进行维护的,数据传给服务器,服务器传给数据库,数据库处理数据生成id)案例中简单处理,按照自增长规律实现自增长。
在人员列表每个人员后面加入输入框,input写在li里面,在input输入框里面添加文字,点击一次性按钮添加人员。
实操过程第一次小白bug记录
最后找到原因是因为
methods应该和data并列而不是和data的内容并列。(透露我是一个小小白)
言归正传,代码正常运行后的截图如下
input输入框的内容因为新添加的人员而错位,原因是index作为key,过程如图,
一样的复用,不一样的生成新的DOM,随后替换页面中之前的真实DOM 如果对顺序做了破坏性操作,index做key会出问题。id作为key就不会有问题,因为id具有唯一性。
面试题
react和vue中的key有什么作用?(key的内部原理)
- 虚拟DOM中key的作用: key是虚拟DOM对象的标识,当状态中的数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】差异比较
- 对比规则 (1)旧的虚拟DOM中找到了和新的虚拟DOM中相同的key: ①若虚拟DOM中内容没变,直接使用之前的真实DOM ②若虚拟DOM中内容改变,则生成新的真实DOM,随后替换页面中之前的真实DOM (2)旧虚拟DOM中未找到与新虚拟DOM相同的key 创建新的真实DOM随后渲染到页面中
- 用index作为key可能引发的问题:
- 若对数据进行:逆序添加,逆序删除等破坏顺序操作,会产生没有必要的真实DOM更新,界面效果没问题但是效率低
- 如果结构中包含输入类的DOM ,会产生错误的DOM更新,界面会有问题
- 开发中如何选择key?
- 最好使用每条数据的唯一标识作为key,比如id,手机号,身份证号,学号等唯一值
- 如果不存在破坏顺序的操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。
列表过滤
通过watch来实现监视变化,当用户输入的keyword发生变化时对数据进行过滤,监视keyWord,因为输入新的值不用关注旧的值所以不用传旧的值的参数。
<div id="filtrate">
<h2>人员列表</h2>
<input type="text" placeholder="请输入名字" v-model="keyWord">
<ul>
<li v-for="(p,index) of persons" :key="index">
{{p.name}}--{{p.age}}--{{p.sex}}
</li>
</ul>
</div>
<script>
const vm = new Vue({
el: '#filtrate',
data: {
keyWord: '',
persons: [
{ id: '001', name: '马冬梅', age: 18, sex: '女' },
{ id: '002', name: '周冬雨', age: 19, sex: '女' },
{ id: '003', name: '周杰伦', age: 20, sex: '男' },
{ id: '004', name: '温兆伦', age: 20, sex: '男' }
],
},
watch: {
keyWord: (val) =>
console.log('keyword被改了', val)
}
})
</script>
在输入框输入文字后
一开始keyWord写的普通函数报错了,(我对普通函数有什么误解) watch里的内容(正确的)
keyWord(val) {
console.log('keyword被改了', val)
}
报错是因为我在keyWord和参数之间写了冒号,就想着这普通函数为啥有毛病了???(实际这真的是普通函数吗哈哈哈) 不过还是建议写成箭头函数
watch: {
keyWord: (val) =>
console.log('keyword被改了', val)
}
判断字符里是否包含指定字符使用indexOf,如果不包含返回-1,如果包含返回字符所在字符串的所在位置的索引值
keyWord(val) {
this.persons = this.persons.filter((p) => {
return p.name.indexOf(val) !== -1
})
}
上述代码可以实现,在输入框输入一个列表中人员的姓或者名,可以显示包含该姓名的人员,但是存在问题 第一次输入冬,显示周冬雨和马冬梅,列表过滤后更新,原来的其余的两个人的数据就丢失了,此时如果搜索周不会显示任何人的信息,如果想保留原数据,可以新建一个数据集合在data里面用来保存过滤后的数据,这样就可以保留原数据在原来的persons数据里面,同时修改上面的遍历的代码"(p,index) of persons"改为"(p,index) of filPersons",但是这样最初打开页面由于filPersons数据是空的所以啥都没有,可以在啥不知道的情况下进行查询然后就会在filPersons保存数据 当输入空字符串的时候会返回所有数据,因为indexOf''会返回所有的数据 如果想要在开始的时候显示所有数据,完整代码如下
keyWord: {
immediate: true,
handler(val) {
this.filPersons = this.persons.filter((p) => {
return p.name.indexOf(val) !== -1
})
}
}
上述代码可以在页面打开的时候调用一次,所以最初的页面会显示所有的数据,下面用computed实现
computed: {
filPersons() {
return this.persons.filter((p) => {
return p.name.indexOf(this.keyWord) !== -1
})
}
}
列表排序
sortType 0原顺序 1降序,2升序 判断是都可以排序 if(this.sortType !==0)也可以写 if(this.sortType),无论是1还是2转成布尔值都是真
先过滤后排序,排序降序是后-前,p1,p2是对象,排序应该是对象的属性,因为改变的是过滤后的数据,所以点击原顺序可以返回最初的不变的数据集
computed: {
filPersons() {
const arr = this.persons.filter((p) => {
return p.name.indexOf(this.keyWord) !== -1
})
// 判断一下是否需要排序
if (this.sortType) {
arr.sort((p1, p2) => {
//函数体
return this.sortType === 1 ? p2.age - p1.age : p1.age - p2.age
})
}
return arr
}
}