文章目录
初学Vue
1、列表渲染
v-for命令和:key属性的使用
1.1 遍历数组类型
示例一:
<!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">
<script src="../../JS/vue.js"></script>
<title>遍历数组</title>
</head>
<body>
<div id="root">
<ul>
<li v-for="p in persons" :key="p.id">
{
{p.id}}-{
{p.name}}-{
{p.age}}
</li>
</ul>
<!-- p in persons中的p是从数组persons中获取到的一个对象,这里相当于迭代器的用法,in再2.6版本后可以改为of -->
<!-- 通过p.id的形式获取对象里面的值 -->
<!-- :key="p.id" 中的:key是标识性属性,相当于给这个元素一个身份识别 -->
<!-- 虽然:key可以省略不写,但原则上不要省略 -->
</div>
<script>
Vue.config.productionTip = false;
const vm = new Vue({
el:"#root",
data:{
// 准备一个数组,存储三个对象
persons:[
{
id:"001",name:"张三",age:"18"},
{
id:"002",name:"李四",age:"20"},
{
id:"003",name:"王五",age:"21"},
]
}
});
</script>
</body>
</html>
示例二:index的使用
<body>
<div id="root">
<ul>
<li v-for="(p,index) in persons" :key="index">
{
{p.id}}-{
{p.name}}-{
{p.age}}-{
{index}}
</li>
</ul>
<!-- index的值由0开始自动自增,数组中由多少项就自增多少次,并且是浏览器决定的,就算不写,浏览器也会把这个值当成默认值 -->
</div>
<script>
Vue.config.productionTip = false;
const vm = new Vue({
el:"#root",
data:{
// 准备一个数组,存储三个对象
persons:[
{
id:"001",name:"张三",age:"18"},
{
id:"002",name:"李四",age:"20"},
{
id:"003",name:"王五",age:"21"},
]
}
});
</script>
</body>
1.2 遍历对象类型
示例三
<!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">
<script src="../../JS/vue.js"></script>
<title>遍历对象</title>
</head>
<body>
<div id="root">
<ul>
<li v-for="(value,key) in car" :key="key">
{
{key}}- {
{value}}
</li>
</ul>
<!-- v-for会将对象中的键值对遍历出来,并且写法是先value,再写key -->
<!-- :key="key" 引号中的key是用来做标识的 -->
</div>
<script>
Vue.config.productionTip = false;
const vm = new Vue({
el:"#root",
data:{
// 准备单独一个对象,对象中有属性
car:{
name:"兰博基尼",
prices:"1400万",
color:"blue"
}
}
});
</script>
</body>
</html>
1.3 遍历字符串
<!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">
<script src="../../JS/vue.js"></script>
<title>遍历字符串</title>
</head>
<body>
<div id="root">
<ul>
<li v-for="(value,index) in str" :key="index">
{
{index}}- {
{value}}
<!-- {
{value}} -->
</li>
</ul>
</div>
<script>
Vue.config.productionTip = false;
const vm = new Vue({
el:"#root",
data:{
str:"hello"
}
});
</script>
</body>
</html>
- 遍历指定次数
<body>
<div id="root">
<ul>
<li v-for="(v,index) in 5" :key="index">
{
{v}}- {
{index}}
<!-- v中是从1开始逐渐自增到5的五个数:1,2,3,4,5-->
<!-- index是从0开始逐渐自增到4 -->
</li>
</ul>
</div>
<script>
Vue.config.productionTip = false;
const vm = new Vue({
el:"#root",
});
</script>
</body>
2、key作用与原理
key的作用和原理是面试中可能问到的问题,所以还是比较重要的,建议慢慢研究
2.1 虚拟DOM中key的作用
key是虚拟DOM对象的表示,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行了【新虚拟DOM】与【旧虚拟DOM】的差异比较。
2.2 新虚拟DOM与旧虚拟DOM的比较规则
(1)旧虚拟DOM中如果找到了和新虚拟DOM相同的key:
1、若对比下来,虚拟DOM中内容没变,直接使用之前的真实DOM,(这也是效率高的一个原因)
2、若对比下来,虚拟DOM中内容变了,则会生成新的真实DOM,随后替换掉页面中之前的真实DOM
(2)旧虚拟DOM中未找到与新虚拟DOM相同的key,则直接创建新的真实DOM,随后渲染到页面。
2.3 如何选择key?
- 最好使用每条数据的唯一标识作为key,比如id,手机好,身份证,学号等能唯一表示身份的值
- 如果不存在对数据的的逆序添加、逆序删除等破坏正常顺序的操作,仅用于渲染列表用于展示,是可以使用index作为key的。
- 如果不在模板中添加key属性,那么浏览器就会默认将index作为可以的值
用index作为key可能引发的问题
1、若对数据进行逆序添加、逆序删除等破化顺序的操作:会产生没有必要的真实DOM更新,这时页面效果可能没有问题,但还是会引起效率变低。
2、如果结构中还包含输入类的DOM,例如input输入框,在逆序操作的过程中,因为会产生错误的DOM更新,也就会引起界面出错。
看下面几个示例:
- 使用index作为key的唯一标识时
示例一:不包含输入框时
<body> <div id="root"> <!-- 这个按钮用于在列表的最前面添加一个数据,并且只添加一次 --> <!-- 如果在列表最后面添加,并不会体现index的问题,这里就不演示了 --> <button @click.once="add">点我添加一个老刘</button> <ul> <li v-for="(p,index) in persons" :key="index"> { {p.name}}-{ {p.age}} </li> </ul> </div> <script> Vue.config.productionTip = false; new Vue({ el:"#root", data:{ persons:[ { id:"001",name:"张三",age:18}, { id:"002",name:"李四",age:19}, { id:"003",name:"王五",age:20}, ] }, methods:{ add(){ const p = { id:"003",name:"王五",age:20}; // 往persons数组最前面中添加数据 this.persons.unshift(p); } } }); </script> </body>
表面上查看页面结果正常,也不报警告和错误。
实际上存在很严重的效率问题,接下来通过给模板添加一个输入框然后分析虚拟DOM的变化来演示下这个问题。
将模板列表添加个输入框<ul> <li v-for="(p,index) in persons" :key="index"> { {p.name}}-{ {p.age}} <input type="text"> </li> </ul>
此时我们往输入框中输入如下数据,然后点击添加
可以发现,输入框中的数据错位了!!原本对应张三-18的输入框中的数据应该也是张三哥-18才对,并且李四和王五应该也是如此才对。
下面具体分析下出现问题的原因:
如下图:
分析:在原数据中对应一个旧的初始虚拟DOM,在添加数据之后,产生一个新的虚拟DOM,浏览器显示的结果是拿这两个新旧虚拟DOM进行对比产生的,这里用到了一个虚拟DOM对比算法,具体描述如下:
(1)在添加新数据之后,新虚拟DOM会和虚拟DOM进行比较,比较的是key值相同的一行,例如key=0时,先比较文本内容,一个是 张三-18,一个是老刘-40,文本内容不同,那么文本就使用新虚拟DOM中的文本,接下来比较子元素input,发现input是相同的,相同就复用旧虚拟DOM中的input,此时旧虚拟DOM中的input输入框中有内容,那么就会同样保存下来。
(2)key=1和key=2比较过程也和(1)一样。下面具体说说key=3的情况
(3)在旧的虚拟DOM中,原本王五-20的key值是2,而到了新虚拟DOM中,王五-20的key值就成了3,而旧虚拟DOM中不存在key=3的内容,所以比较不了,那么就会直接创建新的真实DOM,输入框中也就不会存在内容。
(4)经过虚拟DOM比较之后就可以转换为真实DOM了
补充::key是属于Vue的,当打开页面查看模板时,会发现html代码中并不会出现:key,如下:
为什么用唯一值作为key就不会出错了
如下:
对于key值不存在时则会直接创建新的真实DOM。
3、列表过滤
watch实现
<!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">
<script src="../../JS/vue.js"></script>
<title>watch实现</title>
</head>
<body>
<div id="root">
<h2>人员列表</h2>
<input type="text" placeholder="请输入名字" v-model="keyWord">
<ul>
<li v-for="(p,index) in filPersons" :key="index">
{
{p.name}}-{
{p.age}}-{
{p.sex}}
</li>
</ul>
</div>
<script>
Vue.config.productionTip = false;
const vm = new Vue({
el: "#root",
data: {
keyWord: "",
// 用数组存储
persons: [
{
id: "001", name: "马冬梅", age: 30, sex: "女" },
{
id: "002", name: "周冬雨", age: 28, sex: "女" },
{
id: "003", name: "周杰伦", age: 30, sex: "男" },
{
id: "004", name: "白敬亭", age: 26, sex: "男" },
],
fillPersons: []
},
watch: {
keyWord: {
// 如果要页面加载后就展示所有数据,那么添加下面语句
immediate: true,
// handler(newValue,oldValue)
handler(val) {
// 用一个新数组存储过滤后的数据
this.filPersons = this.persons.filter((p) => {
// indexOf()方法的返回值为-1时表示无匹配数据
return p.name.indexOf(val) !== -1;
// 注意当indexOf中传的是空字符串时,返回值是0,因为还是存储了空字符串,索引为0
})
}
}
}
})
</script>
</body>
</html>
computed实现
<!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">
<script src="../../JS/vue.js"></script>
<title>computed实现</title>
</head>
<body>
<div id="root">
<h2>人员列表</h2>
<input type="text" placeholder="请输入名字" v-model="keyWord">
<ul>
<li v-for="(p,index) in filPersons" :key="index">
{
{p.name}}-{
{p.age}}-{
{p.sex}}
</li>
</ul>
</div>
<script>
Vue.config.productionTip = false;
const vm = new Vue({
el: "#root",
data: {
keyWord: "",
// 用数组存储
persons: [
{
id: "001", name: "马冬梅", age: 30, sex: "女" },
{
id: "002", name: "周冬雨", age: 28, sex: "女" },
{
id: "003", name: "周杰伦", age: 30, sex: "男" },
{
id: "004", name: "白敬亭", age: 26, sex: "男" },
],
},
computed: {
filPersons(){
return this.persons.filter((p)=>{
return p.name.indexOf(this.keyWord) !== -1;
})
}
}
})
</script>
</body>
</html>
4、列表排序
<!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">
<script src="../../JS/vue.js"></script>
<title>列表排序</title>
</head>
<body>
<div id="root">
<h2>人员列表</h2>
<input type="text" placeholder="请输入名字" v-model="keyWord">
<input type="button" value="升序" @click="sortType = 1">
<input type="button" value="降序" @click="sortType = 2">
<input type="button" value="原顺序" @click="sortType = 0">
<ul>
<!-- filPersons是计算属性 -->
<li v-for="(p,index) in filPersons" :key="index">
{
{p.name}}-{
{p.age}}-{
{p.sex}}
</li>
</ul>
</div>
<script>
Vue.config.productionTip = false;
const vm = new Vue({
el: "#root",
data: {
// 输入框中输入的值
keyWord: "",
// 排序方式标记,0表示原顺序,1表示升序,2表示降序
sortType: 0,
// 用数组存储
persons: [
{
id: "001", name: "马冬梅", age: 30, sex: "女" },
{
id: "002", name: "周冬雨", age: 28, sex: "女" },
{
id: "003", name: "周杰伦", age: 30, sex: "男" },
{
id: "004", name: "白敬亭", age: 26, sex: "男" },
],
},
computed: {
filPersons() {
// 先过滤出名字
const arr = this.persons.filter((p) => {
return p.name.indexOf(this.keyWord) !== -1;
});
// 判断是否需要排序,0表示原顺序,其他为排序
if (this.sortType) {
// sort进行排序,返回的是一个新数组
arr.sort((a, b) => {
return this.sortType === 1 ? a.age - b.age : b.age - a.age;
})
};
return arr;
}
}
})
</script>
</body>
</html>