目录
一、条件渲染
当符合某个条件后,我们就选用某种样式
1.1 v-if
适用于:切换频率较低的场景
特点:不展示的DOM元素直接被移除,在页面源码中无法看到
注意:v-if,v-else-if 、 else if,div要紧紧的挨在一起,不能打断
<!-- v-else-if 类似java中if else if判断 -->
<!-- 这四个div要紧紧的挨在一起,不能打断 -->
<div v-if="n===1" >Angular</div>
<div v-else-if="n===2" >React</div>
<div v-else-if="n===3" >Vue</div>
<div v-else >6666666</div>
<!-- 使用v-if做条件渲染:在网页查看源码时,将不会看到下面这个html语句 -->
<h2 v-if="false">欢迎来到{{name}}学习</h2>
下面便是被打断的演示,此时"Vue"与"6666666"就不会再被展示了
<div v-if="n===1" >Angular</div>
<div v-else-if="n===2" >React</div>
<div>React</div>
<div v-else-if="n===3" >Vue</div>
<div v-else >6666666</div>
1.2 v-show
写法:v-show=“表达式”
适用于:切换频率较高的场景
特点:不展示DOM元素未被移除,仅仅是使用上隐藏掉,在页面的源代码中还是能看到的
备注:使用v-if时,元素可能无法获取到,而使用v-show一定可以获取到
备注的意思是使用v-show修饰的元素虽然不在页面中展示,但是可以拿到这个元素的,但是使用v-if的话就拿不到
<!-- 使用v-show做条件渲染:确切的说这个底层是display:none -->
<h2 v-show="false">欢迎来到{{name}}学习</h2>
v-show的底层其实就是调整 style="display:none"的值
1.3 template
当我们对某几个标签添加相同的样式的时候,我们就可以使用template标签,在标签上添加v-if属性
好处:不影响整体样式。
备注:template标签不影响整体结构,只是把下面这三个标签给包裹起来,在页面查看源码的时候也不会发现template标签
此标签只能使用v-if,不能使用v-show
<!-- template标签不影响整体结构,只是把下面这三个标签给包裹起来,在页面查看源码的时候也不会发现template标签
此标签只能使用v-if,不能使用v-show -->
<template v-if="n===1">
<h2>你好</h2>
<h2>中国</h2>
<h2>北京</h2>
</template>
二、列表渲染 v-for
用于展示列表数据
语法:v-for="(item,index) in xxx" :key="yyy"
可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)
2.1 遍历数组
v-for类似java中foreach遍历,persons里面有几个值,我们在页面就会呈现几个
:key="p.id"让每一个li都有一个唯一的标识,类似数据库中的主键
{{p}} 这么输出的话,会把数据直接输出,我们一般不这样
<li v-for="p in persons" :key="p.id">
<!-- {{p}} 这么输出的话,会把数据直接输出,我们一般不这样 -->
{{p.name}}-{{p.age}}
</li>
其实这个地方不写 :key="p.id" 也是可以的,也不会报错,但是最好一定要写上
而且在遍历的时候可以接受好几个参数,比如 (a,b,c) in persons
a代表我们数据
b代表索引值
c及其以后就没有参数了
除此之外,还可以 (p,index) of persons,就是把关键字in换成of,这是API的历史遗留问题
index是索引值,这个地方会有索引值,类似数组的下标 :key="p.id" 这个地方不用p.id也可以,我们使用index ,因为index也是唯一的,类似数组下标 :key这个标签特别重要,动态绑定数据
<ul>
<li v-for="(p,index) in persons" :key="index">
<!-- {{p}} 这么输出的话,会把数据直接输出,我们一般不这样 -->
{{p.name}}-{{p.age}}-{{index}}
</li>
</ul>
如果要有顺序的话,就需要数组来存储 这里的id类似数据库中的主键
data:{
persons:[
{id:'001',name:'张三',age:18},
{id:'002',name:'李四',age:18},
{id:'003',name:'王五',age:20}
]
},
效果图
2.2 遍历对象
<h2>汽车信息</h2>
<ul>
<li v-for="(value,k) in car" :key="k" >
{{value}}-{{k}}
</li>
</ul>
data:{
car:{
name:'奥迪A8',
price:"666666",
color:'黑色'
}
},
效果图
2.3 遍历字符串
<ul>
<li v-for="(value,k) in str" :key="k" >
{{value}}-{{k}}
</li>
</ul>
data:{
str:'hello'
}
2.4 遍历指定次数
第一个参数是数值。第二个参数是索引值
<ul>
<li v-for="(number,index) in 5" :key="index" >
{{number}}-{{index}}
</li>
</ul>
三、列表渲染 key 原理
说白了key就是一个身份表示,类似人的身份证号
如果在写代码时并没有指定:key,我们会把index默认的作为key
通过我们查看发现,我们在源代码中是有:key的,但是在网页上并不会显示,原因就是这个:key是vue内部在用,用完就干掉了
3.1 问题演示
如下, :key值是index的时候,会出现一系列的问题(不同的情景不一样,可能index不会出问题)
添加一个“老刘”角色,将其添加在数组的最前面
<h2>人员列表</h2>
<button @click.once="add">添加一个老刘</button>
<ul>
<!-- key标签属性非常重要 -->
<!-- p代表着persons中的一个对象 -->
<li v-for="(p,index) in persons" :key="index">
{{p.name}}-{{p.age}}-{{index}}
<input type="text">
</li>
</ul>
new Vue({
el: "#root",
data: {
persons: [
{ id: '001', name: '张三', age: 18 },
{ id: '002', name: '李四', age: 18 },
{ id: '003', name: '王五', age: 20 }
]
},
methods:{
add(){
const p ={ id: '004', name: '老刘', age: 18 }
this.persons.unshift(p)
}
}
})
点击按钮后的效果,
演示问题
在文本框中输入内容,之后再点击添加老刘
变成了如下所示的情况,文本框不会随着人名流动
除此之外还存在一个效率低的问题
3.2 解决问题
将key改成p.id即可
<h2>人员列表</h2>
<button @click="add">添加一个老刘</button>
<ul>
<!-- index就是索引值,这个地方会有索引值,类似数组的下标 -->
<!-- :key="p.id" 这个地方不用p.id也可以,我们使用index ,因为index也是唯一的,类似数组下标-->、
<!-- :key这个标签特别重要,动态绑定数据 -->
<li v-for="(p,index) in persons" :key="p.id">
<!-- {{p}} 这么输出的话,会把数据直接输出,我们一般不这样 -->
{{p.name}}-{{p.age}}-{{index}}
<input type="text">
</li>
</ul>
3.3 原理
3.1.1 index 作为 key
假如遍历的时候不指定:key是哪个,也会默认将index作为key
-
Vue将我们写的数据生成虚拟的DOM
真实DOM是没有key的,但是虚拟DOM是有key的,如果虚拟DOM没有key,Vue就没有办法高效的工作了
截止目前,我们的页面啥也没有,只是内存出现了三个结点
-
将虚拟DOM转换成真实DOM
-
用户在真实DOM的文本框输入数据后,新的数据出现。随后就要根据新的数据生成新的虚拟DOM
-
Vue进行虚拟DOM的对比算法,对比的时候依赖的就是key
对比规则
-
旧虚拟DOM找到了与新虚拟DOM相同的key
若虚拟DOM中内容没变,直接使用之前的真实DOM
若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
-
旧虚拟DOM中未找到与新虚拟DOM中相同的key
创建新的真实DOM,随后渲染到页面
-
对比结果
3.1.2 id 作为 key
其实和index作为key差不多
3.4 总结
-
虚拟DOM中key的作用 key是虚拟对象的标识,当数据发生变化时,Vue会根据新数据生成新的虚拟DOM,随后Vue进行新虚拟DOM与旧虚拟DOM的差异比较。
-
对比规则
-
旧虚拟DOM找到了与新虚拟DOM相同的key
若虚拟DOM中内容没变,直接使用之前的真实DOM
若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
-
旧虚拟DOM中未找到与新虚拟DOM中相同的key
创建新的真实DOM,随后渲染到页面
-
-
用index作为key可能引发的问题
-
若对数据进行逆序添加、逆序删除等破坏顺序操作:
会产生没有必要的真实DOM更新==》界面效果没问题,但效率低
-
如果结构中还包含输入类DOM:
会产生错误DOM更新==》界面有问题
-
-
开发中如何选择key?
-
最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等(类似数据库中主键)
-
如果不存在对数据的逆序添加、逆序删除等破坏顺序的操作,仅用于渲染列表用于展示,使用index作为key是没有问题的
-
四、列表过滤
初始界面
4.1 watch 实现
监视属性基础知识:4.Vue-计算属性、监视属性、深度监视、计算属性与监视属性对比计算属性深度我爱布朗熊的博客-CSDN博客
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title> 初识vue</title>
<!--引入vue 引入之后,全局就多了一个vue这个构造函数-->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<div id="root">
<ul>
<h2>人员列表</h2>
<!-- 双向绑定一下 -->
<input type="text" placeholder="请输入名字" v-model="keyWords">
<li v-for="(p,index) in filPersons" :key="p.id" >
{{p.name}}-{{p.age}}-{{p.sex}}
</li>
</ul>
</div>
<script type="text/javascript">
//阻止vue在启动时生成生产提示
Vue.config.productionTip=false
new Vue({
el:'#root',
data:{
//关键词,后面要用这个进行过滤
keyWords:'',
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:'男'}
],
filPersons:[]
},
watch:{
// 监视谁我们就写谁
keyWords:{
// 初始化时让handler调用一下,如果不调用的话,初始页面会没有内容
// 前提条件:所有的字符串.indexOf("")空字符串,返回值都是0
immediate:true,
handler(newValue,oldValue){
// 过滤
// filter规律之后,并不会影响我们初始的数组,而是生成一个全新的数组
// 我们不能更改直接赋值到原数组,否则会导致我们查询的内容越来越少,最后甚至没有了
this. filPersons= this.persons.filter((p)=>{
// 函数体
// return 后面加的语句使我们要的数据
// indexOf 方法(判断字符串里面是否包含指定字符),当含有括号内的字符串的时候,会返回下标是第几位(从零开始算
//当不包含的时候,就会返回-1
return p.name.indexOf(newValue) !==-1
})
}
}
},
methods:{
}
})
</script>
</body>
</html>
4.2 computed 实现
计算属性基础知识:4.Vue-计算属性、监视属性、深度监视、计算属性与监视属性对比计算属性深度我爱布朗熊的博客-CSDN博客
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title> 初识vue</title>
<!--引入vue 引入之后,全局就多了一个vue这个构造函数-->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<div id="root">
<ul>
<h2>人员列表</h2>
<!-- 双向绑定一下 -->
<input type="text" placeholder="请输入名字" v-model="keyWords">
<li v-for="(p,index) in filPersons" :key="p.id" >
{{p.name}}-{{p.age}}-{{p.sex}}
</li>
</ul>
</div>
<script type="text/javascript">
//阻止vue在启动时生成生产提示
Vue.config.productionTip=false
const vm= new Vue({
el:'#root',
data:{
keyWords:'',
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:'男'}
],
},
//在计算属性中依赖了keyWords,当keyWords一变,就会调用filPersons()
computed:{
// 这个形式是缩写,当getter函数使用
// 初次读取的时候会调用一下,当依赖的数据发生变化时也会调用一下
filPersons(){
// 这个return是计算属性规定的
return this.persons.filter((p)=>{
// 这个return是filter规定的
return p.name.indexOf(this.keyWords) !==-1
})
}
}
})
</script>
</body>
</html>
五、列表排序
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title> 初识vue</title>
<!--引入vue 引入之后,全局就多了一个vue这个构造函数-->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<div id="root">
<h2>人员列表</h2>
<!-- 双向绑定一下 -->
<input type="text" placeholder="请输入名字" v-model="keyWords">
<button @click="sortType=2" >年龄升序</button>
<button @click="sortType=1" >年龄降序</button>
<button @click="sortType=0" >原顺序</button>
<ul>
<li v-for="(p,index) in filPersons" :key="p.id" >
{{p.name}}-{{p.age}}-{{p.sex}}
</li>
</ul>
</div>
<script type="text/javascript">
//阻止vue在启动时生成生产提示
Vue.config.productionTip=false
const vm= new Vue({
el:'#root',
data:{
keyWords:'',
// 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:{
// 这个形式是缩写,当getter函数使用
// 初次读取的时候会调用一下,当依赖的数据发生变化时也会调用一下
filPersons(){
// 我们把这个地方的return取消,不着急return
const arr= this.persons.filter((p)=>{
// 这个return是filter规定的
return p.name.indexOf(this.keyWords) !==-1
})
if(this.sortType){
// 运行到这里说明不是0
// sort排序回改变原数组。sort排序的时候会收到两个数据项,前减后是升序,后减前是降序
arr.sort( (p1,p2)=>{
// 三目运算 sortType等于1 年龄降序 sortType等于2 年龄升序
return this.sortType === 1 ? p2.age-p1.age : p1.age-p2.age
})
}
//当 this.sortType===0时,会直接跳过if来到这里(原始数据不会改变,所以就是原顺序
return arr
}
}
})
</script>
</body>
</html>
原顺序:
升序:
降序