Vue核心
# 2.1 模板语法
Vue模板语法包括两大类
# 2.1.1 插值语法
- 功能:用于解析标签体内容
- 写法:`{ {xxx}}`,xxx 是 js 表达式,可以直接读取到 data 中的所有区域
# 2.1.2 指令语法
- 功能:用于解析标签(包括:标签属性、标签体内容、绑定事件…)
- 写法:通过vue的指令将数据绑定到模板上,例如
v-bind:
可以给标签里的属性绑定数据
# 2.2 数据绑定
Vue中有2种数据绑定方法
# 2.2.1 单向数据绑定
v-bind
数据只能从data流入页面- 可以简化为
:
# 2.2.2 双向数据绑定
v-model
数据不仅能从 data 流向页面,还可以从页面流向 datav-model:value
可以简写为v-model
,因为v-model默认收集的就是value值- 双向绑定一般都应用在表单类元素上,如< input>< select>< textarea>等
# 2.2.3 收集表单数据
- 若
<input type="text"/>
,则v-model收集的是value值,用户输入的内容就是value值 - 若
<input type="radio"/>
,则v-model收集的是value值,且要给标签配置value属性 - 若
<input type="checkbox"/>
- 没有配置value属性,那么收集的是checked属性(勾选 or 未勾选,是布尔值)
- 配置了value属性
- v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
- v-model的初始值是数组,那么收集的就是value组成的数组
- v-model修饰符
- lazy 失去焦点后再收集数据
- number输入字符串转为有效的数字
- trim 输入首尾空格过滤
# 2.3 数据代理
数据代理:通过一个对象代理对另一个对象中属性的操作(读写)
# 2.3.1 Vue数据代理原理
- Vue中的数据代理通过vm对象来代理data对象中属性的操作(读/写)
- Vue中数据代理的好处:更加方便的操作data中的数据
- 基本原理
- 通过
Object.defineProperty()
把data对象中所有属性添加到vm上 - 为每一个添加到vm上的属性,都指定一个 getter setter
- 在getter setter内部去操作(读/写)data中对应属性的值
- 其中涉及到Vue将model里的data拷贝到vm的_data属性中,这是为了通过_data对data进行数据劫持,实现页面的响应式展示
- 通过
# 2.3.2 数据代理原理
使用Object.defineProperty()
方法在代理的对象中添加被代理对象需要被代理的属性
let obj = {x:100} //被代理的对象
let propertyObj = {} //代理的对象
Object.defineProperty(propertyObj, 'x', {
//读取propertyObj的x属性时触发
get(){
return obj.x
}
//修改propertyObj的x属性时触发
set(value){
obj.x = value
}
})
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 2.3.3 Object.defineProperty()
let person = {
name:'张三',
sex:'男',
}
let age = 18
// 为person对象添加属性,可以对添加的属性进行高级操作
Object.defineProperty(person, 'age', {
value:18, //属性赋值
enumerable:true, // 控制属性是否可以枚举,默认值是false
writable:true, // 控制属性是否可以被修改,默认值是false
configurable:true // 控制属性是否可以被删除,默认值是false
//当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
get(){
return age
}
//当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
set(value){
age = value
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 2.4 事件处理
# 2.4.1 事件的基本用法
- 使用
v-on:XXX
或@XXX
绑定事件,其中XXX是事件名 - 事件的回调需要配置到在methods对象中,最终会在vm上
- methods中配置的函数,不要用箭头函数,否则 this 就不是vm了
- methods中配置的函数,都是被 Vue所管理的函数,this 的指向是vm或组件实例对象
@click="demo"
和@click="demo($event)"
效果一致,但后者可以传参
# 2.4.2 事件修饰符
- Vue中的事件修饰符
- prevent 阻止默认事件(常用)
- stop 阻止事件冒泡(常用)
- once 事件只触发一次(常用)
- capture 使用事件的捕获模式
- self 只有event.target是当前操作的元素时才触发事件
- passive 事件的默认行为立即执行,无需等待事件回调执行完毕
- 修饰符可以连续写,比如可以这么用:
@click.prevent.stop="showInfo"
# 2.4.3 键盘事件
- 键盘上的每个按键都有自己的名称和编码,例如:Enter(13)。而Vue还对一些常用按键起了别名方便使用
- Vue别名使用
@keyup.enter="XXX"
- . Vue中常用的按键别名
- 回车enter
- 删除delete捕获“删除”和“退格”键
- 退出esc
- 空格space
- 换行tab特殊,必须配合keydown去使用
- 上up;下down ;左left;右right
- Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(多单词小写短横线写法)
- 系统修饰键(用法特殊)ctrlaltshiftmeta(meta就是win键)
- 配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发
- 指定 ctr+y 使用 @keyup.ctr.y
- 配合keydown使用:正常触发事件
- 也可以使用keyCode去指定具体的按键(不推荐)
Vue.config.keyCodes.自定义键名 = 键码
,可以去定制按键别名
# 2.5 计算属性computed
- 定义:要用的属性不存在,需要通过已有属性计算得来
- 原理:底层借助了
Objcet.defineproperty()
方法提供的getter和setter get
函数什么时候执行?- 初次读取时会执行一次
- 当依赖的数据发生改变时会被再次调用
- 优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便
- 计算属性最终会出现在vm上,直接读取使用即可
- 如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变
- 如果计算属性确定不考虑修改,可以使用计算属性的简写形式
const vm = new Vue({
el: '#root',
data: {
firstName:'张',
lastName:'三',
},
computed: {
// 完整写法
fullName: {
get() {
return this.firstName + '-' + this.lastName
},
set(value) {
const arr = value.split('-')
this.firstName = arr[0]
this.lastName = arr[1]
}
}
// 简写
Name() {
return this.firstName + '-' + this.lastName
}
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 2.6监视属性watch
# 2.6.1侦听属性基本用法
- 当被监视的属性变化时,回调函数自动调用,进行相关操作
- 监视的属性必须存在,才能进行监视,既可以监视data,也可以监视计算属性
- 配置项属性
immediate:false
,改为 true,则初始化时调用一次handler(newValue,oldValue)
- 监视有两种写法
- 创建Vue时传入
watch: {}
配置 - 通过
vm.$watch()
监视
- 创建Vue时传入
const vm = new Vue({
el: '#root',
data: {
isHot: true,
},
// 方式一
watch:{
isHot:{
immediate:true,
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
}
},
methods:{
changeWeather(){
this.isHot = !isHot
}
},
computed: {
info(){
return this.isHot ? '炎热' : '凉爽'
}
}
})
// 方式二
vm.$watch('isHot',{
immediate:true,
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 2.6.2 深度监视
- Vue中的watch默认不监测对象内部值的改变(一层)
- 在watch中配置
deep:true
可以监测对象内部值的改变(多层) - Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以
- 使用watch时根据监视数据的具体结构,决定是否采用深度监视
- 只监视多级结构中某个属性的变化
watch(){'numbers.a':{}'}
,key需要手动加''包裹
# 2.6.3 监视属性简写
如果监视属性除了handler没有其他配置项的话,可以进行简写
watch:{
isHot(newValue,oldValue){
}
}
vm.$watch('isHot',(newValue,oldValue){
console.log('isHot被修改了', newValue, oldValue, this)
})
1
2
3
4
5
6
7
2
3
4
5
6
7
# 2.6.4 computed与watch的区别
- computed能完成的功能,watch都可以完成
- watch能完成的功能,computed不一定能完成,例如watch可以进行异步操作
- 所有被Vue管理的函数,最好写成普通函数,这样 this 的指向才是vm或组件实例对象
- 所有不被Vue所管理的函数(定时器的回调函数、ajax 的回调函数等、Promise 的回调函数),最好写成箭头函数,这样 this 的指向才是vm或组件实例对象
# 2.7 样式绑定
# 2.7.1 绑定class样式
- 写法:
:class="xxx"
,xxx 可以是字符串、数组、对象 - 三种写法区别
- 字符串写法适用于:类名不确定,要动态获取
- 数组写法适用于:要绑定多个样式,个数不确定,名字也不确定
- 对象写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用
# 2.7.2 绑定style样式
:style="[a,b]"
其中a、b是样式对象:style="{fontSize: xxx}"
其中 xxx 是动态值
# 2.8 条件渲染
# 2.8.1 v-if
- 写法 跟 if else 语法类似
v-if="表达式"
v-else-if="表达式"
- `v-else
- 适用于:切换频率较低的场景,因为不展示的DOM元素直接被移除
- 注意:
v-if
可以和v-else-if
v-else
一起使用,但要求结构不能被打断
# 2.8.2 v-show
- 写法:
v-show="表达式"
- 适用于:切换频率较高的场景
- 特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉display: none
- 使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到template标签不影响结构,页面html中不会有此标签,但只能配合v-if,不能配合v-sho
# 2.9 列表渲染
# 2.9.1 v-for指令
- 用于展示列表数据
- 语法:
<li v-for="(item, index) of items" :key="index">
,这里key可以是index,更好的是遍历对象的唯一标识 - 可遍历:数组、对象、字符串(用的少)、指定次数(用的少)
# 2.9.2 key的作用与原理
- 虚拟DOM中key的作用:key是虚拟DOM中对象的标识,当数据发生变化时,Vue会根据新数据生成新的虚拟DOM,随后Vue进行新虚拟DOM与旧虚拟DOM的差异比较
- 对比规则
- 旧虚拟DOM中找到了与新虚拟DOM相同的key
- 若虚拟DOM中内容没变, 直接使用之前的真实DOM
- 若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM
- 旧虚拟DOM中未找到与新虚拟DOM相同的key 创建新的真实DOM,随后渲染到到页面
- 旧虚拟DOM中找到了与新虚拟DOM相同的key
- 用index作为key可能会引发的问题
- 若对数据进行逆序添加、逆序删除等破坏顺序操作,会产生没有必要的真实DOM更新 ==> 界面效果没问题,但效率低
- 若结构中还包含输入类的DOM:会产生错误DOM更新 ==> 界面有问题
- 开发中如何选择key
- 最好使用每条数据的唯一标识作为key,比如 id、手机号、身份证号、学号等唯一值
- 如果不存在对数据的逆序添加、逆序删除等破坏顺序的操作,仅用于渲染列表,使用index作为key是没有问题的
- 如果代码没写key,vue就会自动把遍历的index作为key输入
# 2.9.2 列表过滤
v-model
来双向绑定用户过滤的信息- watch实现
- 需要一个新的数组存储过滤后的内容,否则数据越来越少
immediate: true
上来就执行一次,这样过滤后的数组不需要初始给值。其核心原理是任意字符串.indexOf(空字符串) = 0
Array.filter((p)=>{ return p.indexOf(val)})
filter返回一个数组不改变原数组
- computed实现
computed:{
filPersons(){
return this.persons.filter((p)=>{
return p.name.indexOf(this.keyword) !== -1
})
}
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# 2.9.3 列表排序
- 先过滤再排序,在同时存在过滤和排序需求的时候,排序还是维护过滤后的数据
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
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 2.10 内置指令
# 2.10.1之前用过的
- v-bind:单向绑定解析表达式,可简写为
:
- v-model:双向数据绑定
- v-for:遍历数组 / 对象 / 字符串
- v-on:绑定事件监听,可简写为@
- v-show:条件渲染 (动态控制节点是否展示)
- v-if:条件渲染(动态控制节点是否存存在)
- v-else-if:条件渲染(动态控制节点是否存存在)
- v-else:条件渲染(动态控制节点是否存存在)
# 2.10.2 v-text
- 作用:向其所在的节点中渲染文本内容
- 与插值语法的区别:v-text会替换掉节点中的内容,则不会
- 不会解析数据里的html标签
# 2.10.3 v-html
- 作用:向指定节点中渲染包含html结构的内容
- 与插值语法的区别:
- v-html会替换掉节点中所有的内容,则不会
- v-html可以识别html结构
- 严重注意v-html有安全性问题!!!
- 在网站上动态渲染任意html是非常危险的,容易导致 XSS 攻击
- 一定要在可信的内容上使用v-html,永远不要用在用户提交的内容上!!!
# 2.10.4 v-cloak
- 没有值
- 本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性
- 使用css配合v-cloak可以解决网速慢时页面展示出的问题
# 2.10.5 v-once
- v-once所在节点在初次动态渲染后,就视为静态内容了
- 以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能
# 2.10.6 v-pre
- 跳过v-pre所在节点的编译过程
- 可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译
# 2.11 自定义指令
- directives配置项
// 局部指令
new Vue({
directives:{
指令名:配置对象
}
})
new Vue({
directives:{
指令名:(element,binding){}
}
})
// 全局指令
Vue.directive(指令名, 配置对象)
Vue.directive(指令名, 回调函数)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
- element就是DOM元素
- binding就是要绑定的对象,它包含以下属性:name、value、oldValue、expression、arg、modifiers
- 用函数的形式定义时指令执行时间
- 指令与元素成功绑定时
- 指令所在的模板被重新解析时
- 配置对象中常用的三个回调函数
bind(element, binding)
指令与元素成功绑定时调用inserted(element, binding)
指令所在元素被插入页面时调用update(element, binding)
指令所在模板结构被重新解析时调用
- 指令定义时不加v-,但使用时要加v-
- 指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名
- 指令回调函数里的this都是window
# 2.12 过滤器(Vue3已移除)
- 定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)
- 注册过滤器:
- Vue.filter(name, callback)全局过滤器
- new Vue {filters: {}} 局部过滤器
- 使用过滤器: 或 v-bind:属性 = "xxx | 过滤器名"
- 过滤器可以接收额外参数,多个过滤器也可以串联
- 并没有改变原本的数据,而是产生新的对应的数据
上次更新: 2022/06/24, 10:36:25