01-v-if指令
指令名称 | 指令作用 | 示例 | 简写形式 |
---|---|---|---|
v-if | 根据条件渲染数据 | v-if="score>=90" | 无 |
v-show | 设置元素的display | v-show="age>=30" | 无 |
-
v-if官网文档:API — Vue.js
<!-- 1.学习目标: v-if指令 2.学习路线: (1)作用: 根据条件渲染数据 (2)语法: 单分支: v-if="条件语句" 双分支: v-else 多分支: v-else-if="条件语句" (3)注意点 v-else与v-else-if的前面 必须要有 v-if 或者 v-else-if -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<!-- 导包 -->
<script src="./vue.js"></script>
</head>
<body>
<!-- HTML结构 -->
<div id="app">
<!-- lazy :懒加载,输入框失去焦点vue才会渲染数据 -->
<input type="text" v-model.lazy="score" placeholder="请输入考试分数">
<h2>你的考试分数为:{{ score }}</h2>
<hr>
<h3 v-if="score>=90">爸爸给你买法拉利</h3>
<h3 v-else-if="score>=80">爸爸给你买保时捷</h3>
<h3 v-else-if="score>=60">爸爸给你买奥迪</h3>
<h3 v-else>爸爸给你爱的掌声</h3>
</div>
<!--
1.学习目标: v-if指令
2.学习路线:
(1)作用: 根据条件渲染数据
(2)语法:
单分支: v-if="条件语句"
双分支: v-else
多分支: v-else-if="条件语句"
(3)注意点
v-else与v-else-if的前面 必须要有 v-if 或者 v-else-if
-->
<script>
/* 创建vue实例 */
let app = new Vue({
//el:挂载点
el: '#app',
//data: 要渲染的数据
data: {
score: '',
}
})
</script>
</body>
</html>
02-v-show指令
-
v-show官网文档:API — Vue.js
<!-- 1.学习目标: v-show 指令 2.学习路线: (1)作用: 设置元素的display属性值 (2)语法: v-show="属性值" 属性值为true: 元素的display:block 属性值为false: 元素的display:none (3)v-show与v-if区别 v-if : 条件渲染。 如果不满足条件,则该元素不会添加到DOM树中 v-show: 显示与隐藏。 只是修改元素的display属性值 -->
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <!-- 导包 --> <script src="./vue.js"></script> </head> <body> <!-- HTML结构 --> <div id="app"> <p v-if="age>=30">我是v-if渲染出来的</p> <p v-show="age>=30">我是v-show渲染出来的</p> </div> <!-- 1.学习目标: v-show 指令 2.学习路线: (1)作用: 设置元素的display属性值 (2)语法: v-show="属性值" 属性值为true: 元素的display:block 属性值为false: 元素的display:none (3)v-show与v-if区别 v-if : 条件渲染。 如果不满足条件,则该元素不会添加到DOM树中 v-show: 显示与隐藏。 只是修改元素的display属性值 --> <script> /* 创建vue实例 */ let app = new Vue({ //el:挂载点 el: '#app', //data: 要渲染的数据 data: { age: 20, } }) </script> </body> </html>
==知识点验收==
思考题1:v-if和v-show在功能上有什么区别?
v-show
:一定会渲染,只是修改display属性
v-if
:根据条件渲染
思考题2:列举v-if和v-show的使用场景(结合目前学过的案例
v-show : 频繁切换
。 tab栏,鼠标移入移出隐藏
03-【面试题】v-if和v-show区别
-
vue官方文档:条件渲染 — Vue.js
-
1.v-if : 本质是在动态的创建 或者 删除元素节点
-
应用场景:如果是不用频繁切换, 要么显示, 要么隐藏的情况, 适合于用 v-if
-
v-if 是惰性的, 如果初始值为 false, 那么这些元素就直接不创建了, 节省一些初始渲染开销
-
-
-
2.v-show: 本质是在控制元素的 css 样式,
display: none;
-
应用场景:如果是频繁的切换显示隐藏, 用 v-show
-
v-if, 频繁切换会大量的创建和删除元素, 消耗性能
-
-
-
面试题v-if和v-show区别面试题逐字稿参考:
-
面试官你好,我是这么理解v-if和v-show的。 v-if本质其实是动态的创建 或者 删除元素节点。一般不用频繁切换, 要么显示, 要么隐藏的情况, 我都会用 v-if。因为v-if 是惰性的, 如果初始值为 false, 那么这些元素就直接不创建了, 这样就可以节省一些初始渲染开销。v-show本质是在控制元素的 css 样式,display: none;,一般元素需要频繁的切换显示隐藏, 用 v-show。因为v-if在频繁切换会大量的创建和删除元素, 消耗性能。
-
04-vue的key值作用(了解)
-
key值介绍:
-
官方文档:v-if使用key
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <!-- 导包 --> <script src="./vue.js"></script> </head> <body> <!-- HTML结构 --> <div id="app"> <button v-text="type" @click="flag=!flag;type=flag?'手机号注册':'邮箱注册'" ></button> <div v-if="flag" key="phone"> 手机号:<input type="text" placeholder="请输入手机号"> <br> 验证码:<input type="text" placeholder="请输入验证码"> </div> <div v-else> 邮箱:<input type="text" placeholder="请输入邮箱"> <br> 密码:<input type="text" placeholder="请输入邮箱密码"> </div> </div> <script> /* 1.学习目标 : vue中key值作用 * (1)让vue准确的识别DOM元素 (类似于给元素添加一个身份证) * (2)让vue强制更新DOM 2.应用场景: 2.1 使用v-if 切换元素 * 什么时候用key值 : 切换的元素dom结构一致 2.2 使用v-for 渲染列表 * 什么时候用key值 :所有的v-for推荐全部加上key值 */ /* 创建vue实例 */ var app = new Vue({ //el:挂载点 el: '#app', //data: 要渲染的数据 data: { flag: true, type: '手机号注册' } }) </script> </body> </html>
==知识点验收==
-
问题1:
:key="值"
key值的作用是什么? -
问题2:key值实际应用场景?
05-虚拟DOM和diff算法
1.1-虚拟DOM
-
1.vue底层会把挂载点中的真实DOM结构,转变为虚拟DOM。
-
真实DOM : 我们webapi学习的dom对象, 一个对象里面有几百个属性
-
虚拟DOM :
本质是一个js对象
,只处理一些关键的属性。(其他的不处理)
-
-
这是vue的挂载dom
<template> <div id="app"> <p class="my_p">123</p> </div> </template>
-
对应的虚拟DOM结构
const dom = { type: 'div', attributes: [{id: 'box'}], children: { type: 'p', attributes: [{class: 'my_p'}], text: '123' } }
-
2.vue是如何更新渲染数据呢
-
生成新的虚拟DOM结构
-
把几百个dom属性,变成虚拟dom十几个关键属性
-
-
和旧的虚拟DOM结构对比(diff算法)
-
找不不同, 只更新变化的部分(重绘/回流)到页面 - 也叫打补丁
-
==好处1: 提高了更新DOM的性能(不用把页面全删除重新渲染)==
==好处2: 虚拟DOM只包含必要的属性(没有真实DOM上百个属性)==
-
3.总结
-
虚拟DOM是什么?
-
本质就是一个JS对象, 保存DOM关键信息
-
-
虚拟DOM的好处?
-
提高DOM更新的性能, 不频繁操作真实DOM, 在内存中找到变化部分, 更新真实DOM
-
-
1.2-diff算法
vue就地复用策略:Vue会尽可能的就地(同层级,同位置),对比虚拟dom,复用旧dom结构,进行差异化更新。
虚拟dom: 本质就是一个个保存节点信息, 属性和内容的 描述真实dom的 JS 对象
diff算法:
-
策略1:
先同层级根元素比较,如果根元素变化,那么不考虑复用,整个dom树删除重建
先同层级根元素比较,如果根元素不变,对比出属性的变化更新,并考虑往下递归复用。
-
策略2:
对比同级兄弟元素时,默认按照下标进行对比复用。
对比同级兄弟元素时,如果指定了 key,就会 按照相同 key 的元素 来进行对比。
06-v-for指令key值说明
-
官方文档:v-for使用key
v-for指令使用key值几种情况
1.没有key值: 就地更新
2.key值为下标 : 就地更新 (与不设置key值没有区别)
3.key值为id (唯一字符串): 复用相同的key, 更新不同的key
* 同级父元素中,子元素的key值必须是唯一的,否则vue会报错。(类似于相同作用于变量名不能重复)
总结: v-for指令的key值优先使用唯一字符串(性能最高), 实在没有就用下标index
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <!-- 导包 --> <script src="./vue.js"></script> </head> <body> <!-- HTML结构 --> <div id="app"> <ul> <li v-for="(item,index) in list" :key="item.id"> <span>姓名:{{ item.name }}</span> <span>年龄:{{ item.age }}</span> </li> </ul> </div> <script> /* v-for指令使用key值几种情况 1.没有key值: 就地更新 2.key值为下标 : 就地更新 (与不设置key值没有区别) 3.key值为id (唯一字符串): 复用相同的key, 更新不同的key * 同级父元素中,子元素的key值必须是唯一的,否则vue会报错。(类似于相同作用于变量名不能重复) 总结: v-for指令的key值优先使用唯一字符串(性能最高), 实在没有就用下标index */ /* 创建vue实例 */ var app = new Vue({ //el:挂载点 el: '#app', //data: 要渲染的数据 data: { list:[ {id:'21378',name:'张三',age:20}, {id:'12456',name:'李四',age:22}, {id:'39862',name:'王五',age:30}, ] } }) </script> </body> </html>
07-v-for更新检测
1.数组的方法分为两种 第一种: 会改变原数组的元素值, 例如 reverse()、pop()、push()等 * 这种情况 v-for也会更新 第二种:不会改变原数组的元素值. 例如 slice() 、 filter() 、 concat()等 * 这种情况 v-for不会更新
2.总结 : 如果v-for没有更新. 可以覆盖整个数组, 或 使用 vue.$set() 强制更新
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <!-- 导包 --> <script src="./vue.js"></script> </head> <body> <!-- HTML结构 --> <div id="app"> <ul> <li v-for="item in list" > {{ item }} </li> </ul> <button @click="revBtn">数组翻转</button> <button @click="sliceBtn">截取前2个</button> <button @click="updateBtn">更新第一个元素值</button> </div> <script> /* v-for更新检测 1.数组的方法分为两种 第一种: 会改变原数组的元素值, 例如 reverse()、pop()、push()等 * 这种情况 v-for也会更新 第二种:不会改变原数组的元素值. 例如 slice() 、 filter() 、 concat()等 * 这种情况 v-for不会更新 2.总结 : 如果v-for没有更新. 可以覆盖整个数组, 或 使用 vue.$set() 强制更新 */ /* 创建vue实例 */ var app = new Vue({ //el:挂载点 el: '#app', //data: 要渲染的数据 data: { list: [ 10,20,30,40,50 ] }, //methods:事件处理函数 methods: { revBtn() { // 1. 数组翻转可以让v-for更新 this.list.reverse() }, sliceBtn() { // 2. 数组slice方法不会造成v-for更新 /* 原因:slice没有改变原始数组,只是从原始数组中获取元素 解决方案: 覆盖原始数组 */ let newArr = this.list.slice(0, 2) this.list = newArr }, updateBtn() { // 3. 替换元素值,不会造成v-for更新 // this.list[0] = 88 /* 解决方案: this.$set() 参数1: 更新目标结构 参数2: 更新位置 参数3: 更新值 */ this.$set(this.list, 0, 88) } } }) </script> </body> </html>
这些方法会触发数组改变, v-for会监测到并更新页面
-
push()
-
pop()
-
shift()
-
unshift()
-
splice()
-
sort()
-
reverse()
这些方法不会触发v-for更新
-
slice()
-
filter()
-
concat()
注意: vue不能监测到数组里赋值的动作而更新, 如果需要请使用Vue.set() 或者this.$set(), 或者覆盖整个数组
总结: 改变原数组的方法才能让v-for更新
08-vue计算属性
-
vue计算属性官方文档:计算属性和侦听器 — Vue.js
-
1.计算属性作用 : 解决渲染数据的代码冗余问题
-
某些数据在渲染的时候,可能要经过一些复杂逻辑的计算处理
-
-
2.计算属性的语法:
在vue实例的computed对象中声明一个函数
-
这个
函数名
就是
计算属性的属性名
-
在这个函数中 return
返回值
(是
计算属性的属性值
)
-
-
3.注意点
-
这个函数一定要写在vue实例的computed对象中
-
这个函数一定要有返回值,否则计算属性无法渲染
-
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <!-- 导包 --> <script src="./vue.js"></script> </head> <body> <!-- HTML结构 --> <div id="app"> <p>{{ msg }}</p> <p>{{ revMsg }}</p> <p>{{ revMsg }}</p> <p>{{ revMsg }}</p> <p>{{ revMsg }}</p> <p>{{ revMsg }}</p> </div> <!-- 1.学习目标: vue计算属性 2.学习路线: (1)计算属性作用: 解决模板语法代码冗余问题 * 场景 : 数据需要通过计算才能得到 (2)计算属性语法 computed : { 计算属性名(){ return 计算属性值 } } (3)注意点 a. 计算属性要写在vue实例computed中 b. 计算属性函数一定要有返回值 (4)计算属性缓存机制 a. 当第一次使用计算属性的时候, vue会调用一次函数。然后把函数名和返回值平铺到vue实例中。 b. 之后使用计算属性, vue不会调用这个函数,而是从缓存中直接读取。 c. 只有当计算属性内部的数据发生变化的时候,才会重新执行一次这个函数,然后又放入缓存 --> <script> /* 创建vue实例 */ let app = new Vue({ // 1. el:挂载点 el: '#app', // 2.data: 要渲染的数据 data: { msg: '我爱敲代码', }, // 3.methods:事件方法 // 4.computed:计算属性 computed:{ revMsg(){ console.log(1) return this.msg.split('').reverse().join('') } } }) </script> </body> </html>
==知识点验收==
-
问题1:计算属性主要是用于解决什么问题的?
-
解决data中数据渲染冗余问题
-
-
问题2:计算属性好处
-
缓存功能
-
当计算属性依赖值不变,直接从缓存读取
-
当计算属性依赖值发生变化,vue会重新执行一次函数,并且将返回值放入缓存中
-
-
09-计算属性的set与get方法
-
官方文档:计算属性和侦听器 — Vue.js
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <!-- 导包 --> <script src="./vue.js"></script> </head> <body> <!-- HTML结构 --> <div id="app"> 全名:<input type="text" placeholder="请输入你的全名" v-model="fullName"> <br> 姓氏:<input type="text" placeholder="请输入你的姓氏" v-model="firstName"> <br> 名字:<input type="text" placeholder="请输入你的名字" v-model="lastName"> </div> <script> /* 1. 默认情况下,计算属性只有get方法。只能获取,不能修改。否则程序会报错 2. 如果希望计算属性可以修改,则可以实现set方法 */ /* 创建vue实例 */ var app = new Vue({ //el:挂载点 el: '#app', //data: 要渲染的数据 data: { firstName:'', lastName:'', }, //计算属性 computed:{ /*计算属性两种写法 (1)fullName(){} : 默认就是get函数, 无法添加set函数 (2)fullName:{ get(){},set(val){} } : 如果想要添加set函数,计算属性就需要写成对象格式 */ fullName:{ //获取计算属性 get(){ return `${this.firstName}${this.lastName}` }, //设置计算属性 set(val){ console.log(val)//设置的值 this.firstName = val[0] || '' this.lastName = val.substr(1,val.length-1) } } } }) </script> </body> </html>
11-侦听器使用
-
官方文档:侦听器
watch:{
'要侦听的属性名'(newVal,oldVal){ }
}
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <!-- 导包 --> <script src="./vue.js"></script> </head> <body> <!-- HTML结构 --> <div id="app"> 用户名: <input type="text" placeholder="请输入用户名" v-model="username"><span>{{ info }}</span> <br> 密码: <input type="text" placeholder="请输入密码" v-model="password"> </div> <script> /* 1.侦听器作用 : 监听某一个数据变化 2.侦听器语法 : 在vue实例的watch对象中 '要侦听的属性名'(newVal,oldVal){ } 3.面试点 : 侦听器与计算属性区别 计算属性 : 监听多个属性 (只要计算属性内部的任何属性变化,都会执行函数) 侦听器 : 监听单个属性 */ /* 创建vue实例 */ let app = new Vue({ //el:挂载点 el: '#app', //data: 要渲染的数据 data: { username: '', password: '', info:'' }, //计算属性 watch: { username(newVal, oldVal) { console.log(newVal, oldVal) this.info = '验证中...' //模拟网络请求 setTimeout(()=>{ this.info = '该用户已被注册' },500) } } }) </script> </body> </html>
12-深度侦听
watch: {
"要侦听的属性名": {
deep: true, // 深度侦听复杂类型内变化
handler (newVal, oldVal) {}
}
}
-
深度侦听:侦听引用类型内部数据变化
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <!-- 导包 --> <script src="./vue.js"></script> </head> <body> <!-- HTML结构 --> <div id="app"> 用户名: <input type="text" placeholder="请输入用户名" v-model="user.username"><span>{{ info }}</span> <br> 密码: <input type="text" placeholder="请输入密码" v-model="user.password"> </div> <script> /* 1.深度侦听作用 : 侦听引用类型内部数据变化 2.语法: watch: { "要侦听的属性名": { deep: true, // 深度侦听复杂类型内变化 handler (newVal, oldVal) {} } } */ /* 创建vue实例 */ let app = new Vue({ //el:挂载点 el: '#app', //data: 要渲染的数据 data: { user: { username: '', password: '' }, info: '' }, //计算属性 watch: { user: { deep: true, handler(newVal, oldVal) { console.log(newVal, oldVal) this.info = '验证中...' //模拟网络请求 setTimeout(() => { this.info = '该用户已被注册' }, 500) } } } }) </script> </body> </html>
:vue虚拟dom算法与key值工作原理
1.1-虚拟DOM
-
1.vue底层会把挂载点中的真实DOM结构,转变为虚拟DOM。
-
真实DOM : 我们webapi学习的dom对象, 一个对象里面有几百个属性
-
虚拟DOM :
本质是一个js对象
,只处理一些关键的属性。(其他的不处理)
-
-
这是vue的挂载dom
<template> <div id="app"> <p class="my_p">123</p> </div> </template>
-
对应的虚拟DOM结构
const dom = { type: 'div', attributes: [{id: 'box'}], children: { type: 'p', attributes: [{class: 'my_p'}], text: '123' } }
-
2.vue是如何更新渲染数据呢
-
生成新的虚拟DOM结构
-
把几百个dom属性,变成虚拟dom十几个关键属性
-
-
和旧的虚拟DOM结构对比(diff算法)
-
找不不同, 只更新变化的部分(重绘/回流)到页面 - 也叫打补丁
-
==好处1: 提高了更新DOM的性能(不用把页面全删除重新渲染)==
==好处2: 虚拟DOM只包含必要的属性(没有真实DOM上百个属性)==
-
3.总结
-
虚拟DOM是什么?
-
本质就是一个JS对象, 保存DOM关键信息
-
-
虚拟DOM的好处?
-
提高DOM更新的性能, 不频繁操作真实DOM, 在内存中找到变化部分, 更新真实DOM
-
-
1.2.key作用与原理
无key - 就地更新
v-for不会移动DOM, 而是尝试复用, 就地更新,如果需要v-for移动DOM, 你需要用特殊 attribute key
来提供一个排序提示
<ul id="myUL"> <li v-for="str in arr"> {{ str }} <input type="text"> </li> </ul> <button @click="addFn">下标为1的位置新增一个</button>
export default { data(){ return { arr: ["老大", "新来的", "老二", "老三"] } }, methods: { addFn(){ this.arr.splice(1, 0, '新来的') } } };
旧 - DOM结构 和 新 - DOM结构 对比过程
==性能不高, 从第二个li往后都更新了==
有key - 值为索引 - 就地更新
-
还是就地更新
因为新旧虚拟DOM对比, key存在就复用此标签更新内容, 如果不存在就直接建立一个新的
<ul id="myUL"> <li v-for="(str, index) in arr" :key="index"> {{ str }} <input type="text"> </li> </ul> <button @click="addFn">下标为1的位置新增一个</button>
export default { data(){ return { arr: ["老大", "新来的", "老二", "老三"] } }, methods: { addFn(){ this.arr.splice(1, 0, '新来的') } } };
key为索引-图解过程 (又就地往后更新了)
-
v-for先循环产生新的DOM结构, key是连续的, 和数据对应
-
然后比较新旧DOM结构, 找到区别, 打补丁到页面上
最后补一个li, 然后从第二个往后, 都要更新内容
口诀: key的值有id用id, 没id用索引
有key - 值为id - 性能最高
key的值只能是唯一不重复的, 字符串或数值
v-for不会移动DOM, 而是尝试复用, 就地更新,如果需要v-for移动DOM, 你需要用特殊 attribute key
来提供一个排序提示
新DOM里数据的key存在, 去旧的虚拟DOM结构里找到key标记的标签, 复用标签
新DOM里数据的key存在, 去旧的虚拟DOM结构里没有找到key标签的标签, 创建
旧DOM结构的key, 在新的DOM结构里没有了, 则==移除key所在的标签==
<template> <div> <ul> <li v-for="obj in arr" :key="obj.id"> {{ obj.name }} <input type="text"> </li> </ul> <button @click="btn">下标1位置插入新来的</button> </div> </template> <script> export default { data() { return { arr: [ { name: '老大', id: 50 }, { name: '老二', id: 31 }, { name: '老三', id: 10 } ], }; }, methods: { btn(){ this.arr.splice(1, 0, { id: 19, name: '新来的' }) } } }; </script> <style> </style>
图解效果:
总结: 不用key也不影响功能(就地更新), 添加key可以提高更新的性能