文章目录
- 前言
- 列表的基本使用
- Key的原理
- 列表过滤
- 列表排序
前言
本篇文章讲述Vue中最基本的列表使用,如何迭代列表取值,如何对列表进行过滤、排序等。
列表的基本使用
在Vue中使用列表的时候灰常简单,只需要将Vue属性内的列表数据与dom标签进行绑定即可,使用固定的指令v-for可以迭代列表并渲染出包含数据的dom元素。以下是v-for指令的基本用法:
v-for的用法:
用于展示列表数据
语法:v-for="(p.index) in[of] xxx" :key="..."
这里的xxx可以是数组、对象、字符串、指定的循环次数
这个key的作用官方是这么解释的
key属性主要用在Vue的虚拟DOM算法,在新旧nodes对比时辨识VNodes;
如果不使用key,Vue会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法;
而使用key时,它会基于key的变化重新排列元素顺序,并且会移除/销毁key不存在的元素;
后面会针对性分析key的用处与原理,以及vue的diff算法。
效果如下:
代码:
<!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>Document</title>
<script type="text/javascript" src="../js/vue.js"></script>
<style>
li{
font-size: 25px;
}
</style>
</head>
<body>
<div id="demo">
<!-- 遍历数组 -->
<ul>
<li v-for="p in persons" :key="p.id">
{{p.id}}--{{p.name}}--{{p.age}}
</li>
</ul>
<!-- 遍历对象 -->
<ul>
<li v-for="(k,v) in school">
{{v}}:{{k}}
</li>
</ul>
<!-- 遍历字符串 -->
<ul>
<li v-for="(p,index) in s">
{{index}}:{{p}}
</li>
</ul>
<!-- 遍历指定次数 -->
<ul>
<li v-for="(p,index) of n">Hello{{p}}:{{index}}</li>
</ul>
</div>
</body>
<script>
let vm=new Vue({
el:"#demo",
data:{
// 准备工作数组
persons:[
{id:"001",name:"张三",age:40},
{id:"002",name:"张四",age:44},
{id:"003",name:"张五",age:45},
{id:"004",name:"李三",age:45},
{id:"005",name:"李四",age:40},
{id:"006",name:"李五",age:44},
{id:"007",name:"王三",age:45},
{id:"008",name:"王四",age:45},
{id:"009",name:"王五",age:45}
],
//准备工作对象
school:{
name:"南阳理工学院",
cls:"工科",
include:"15个教学院"
},
// 准备工作字符串
s:"Hello",
// 准备工作循环次数
n:5
}
})
</script>
</html>
Key的原理
先来看一个面试题:react、vue中的key有什么作用?(key的内部原理)
1. 虚拟DOM中key的作用:
key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,
随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
2.对比规则:
(1).旧虚拟DOM中找到了与新虚拟DOM相同的key:
①.若虚拟DOM中内容没变, 直接使用之前的真实DOM!
②.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。
(2).旧虚拟DOM中未找到与新虚拟DOM相同的key
创建新的真实DOM,随后渲染到到页面。
3. 用index作为key可能会引发的问题:
1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:
会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
2. 如果结构中还包含输入类的DOM:
会产生错误DOM更新 ==> 界面有问题。
4. 开发中如何选择key?:
1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,
使用index作为key是没有问题的。
列表过滤
列表过滤实际是一个模糊搜索得过程,通过filter过滤器将需要的数据筛选出来
过滤方式有两种:
数据监视:
通过监视搜索框内的数据是否变化,一旦有了变化立即进行筛选
计算属性:
将要展示得内容作为计算属性,进行筛选,当搜索框的数据有变化时就对要展示得内容进行计算
过滤之前:
过滤之后:
原理:
监视搜索框绑定的属性,当属性值发生变化之后就对展示的列表进行过滤,列表是Vue的属性,所以改变之后会重新渲染页面。
源代码:
<!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>Document</title>
<script type="text/javascript" src="../js/vue.js"></script>
<style>
table{
width: 100%;
}
</style>
</head>
<body>
<div id="demo">
搜索:<input type="text" v-model="searched" />
<table border="true">
<tr>
<th>学号</th>
<th>姓名</th>
<th>年龄</th>
</tr>
<tr v-for="p in templs">
<th>{{p.id}}</th>
<th>{{p.name}}</th>
<th>{{p.age}}</th>
</tr>
</table>
</div>
</body>
<script>
let vm = new Vue({
el: "#demo",
data: {
searched: "",
persons: [
{ id: "001", name: "张三", age: 40 },
{ id: "002", name: "张四", age: 44 },
{ id: "003", name: "张五", age: 45 },
{ id: "004", name: "李三", age: 45 },
{ id: "005", name: "李四", age: 40 },
{ id: "006", name: "李五", age: 44 },
{ id: "007", name: "王三", age: 45 },
{ id: "008", name: "王四", age: 45 },
{ id: "009", name: "王五", age: 45 },
]
},
// 使用watch监视属性进行实现
/*watch:{
// 这里是个编程小技巧,""空字符串被包含在所由字符串内
// 如果一个字符串为abc那么a与空字符得索引都为0
// 可以使用indexOf进行位置得判定
searched:{
immediate:true,
handler(val){
this.templs=this.persons.filter((p)=>{
return (p.name.indexOf(val)!=-1)
})
}
}
}*/
//使用计算属性进行实现
computed:{
templs(){
return this.persons.filter((p)=>{
return p.name.indexOf(this.searched)!=-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>Document</title>
<script type="text/javascript" src="../js/vue.js"></script>
<style>
table{
width: 100%;
}
</style>
<!--
加入排序功能,排序与过滤其实需要一块操作
-->
</head>
<body>
<div id="demo">
搜索:<input type="text" v-model="searched" />
<button @click="nammol">点我原序</button>
<button @click="esc">点我升序</button>
<button @click="cesc">点我降序</button>
<table border="true">
<tr>
<th>学号</th>
<th>姓名</th>
<th>年龄</th>
</tr>
<tr v-for="p in templs">
<th>{{p.id}}</th>
<th>{{p.name}}</th>
<th>{{p.age}}</th>
</tr>
</table>
</div>
</body>
<script>
let vm = new Vue({
el: "#demo",
data: {
searched: "",
persons: [
{ id: "001", name: "张三", age: 40 },
{ id: "002", name: "张四", age: 44 },
{ id: "003", name: "张五", age: 45 },
{ id: "004", name: "李三", age: 45 },
{ id: "005", name: "李四", age: 40 },
{ id: "006", name: "李五", age: 44 },
{ id: "007", name: "王三", age: 45 },
{ id: "008", name: "王四", age: 45 },
{ id: "009", name: "王五", age: 45 },
],
tag:0, //0原顺序 1升序 2降序
templs:[]
},
methods: {
nammol() {
this.tag=0
},
esc(){
this.tag=1
},
cesc(){
this.tag=2
}
},
// 使用watch监视属性进行实现数据的筛选及排序
watch:{
// 如果只监测一个search属性得话,没有办法在点击排序的时候进行排序
searched:{
//页面初次装载完毕执行一次。
immediate:true,
handler(val){
this.templs=this.persons.filter((p)=>{
return (p.name.indexOf(val)!=-1)
})
if (this.tag){
this.templs.sort((v1,v2)=>{
return this.tag===1?v2.age-v1.age:v1.age-v2.age
})
}
}
},
//针对已经过滤出来的数据进行排序,如果是原序输出就重新筛选一遍(如果不写这个当tag做出改变的时候并不会有dom响应)
tag:{
handler(){
if (this.tag){
this.templs.sort((v1,v2)=>{
return this.tag===1?v2.age-v1.age:v1.age-v2.age
})
}
else{
this.templs=this.persons.filter((p)=>{
return (p.name.indexOf(this.searched)!=-1)
})
}
}
}
}
//使用计算属性进行实现
// computed:{
// templs(){
// const temp= this.persons.filter((p)=>{
// return p.name.indexOf(this.searched)!=-1
// })
// if (this.tag){
// temp.sort((v1,v2)=>{
// return this.tag===1?v2.age-v1.age:v1.age-v2.age
// })
// }
// return temp
// }
// }
});
</script>
</html>