Vue 基础
本文将介绍 Vue 的基础语法。
一、实例参数
1 |
|
创建 Vue 实例时,需要为其传入参数,其中:
1. el
决定了 Vue 实例将会管理哪一个元素。
2. data
Vue 实例对应的数据对象。
3. methods
定义属于 Vue 实例的方法。
二、响应式
1. 响应式属性
当一个 Vue 实例被创建时,它会将 data 中的所有属性都加入响应式系统中。当这些值发生改变时,自动发生响应,视图发生改动。
2. 注意事项
需要注意的是:只有当创建实例时就已经存在于 data 中的值才会发生响应。如果在定义了 Vue 实例以后,再为实例添加新的属性,则对该属性的改动将不会触发视图的更新。
如果需要为属性“占坑”,可以在创建 Vue 实例时,为属性设置空的初始值。
1
2
3
4
5
6
7data: {
newTodoText: '',
visitCount: 0,
hideCompletedTodos: false,
todos: [],
error: null
}
3. Object.freeze()
并且,如果使用了 JavaScript 中的 Object.freeze()
方法,则无法改动该对象,因此也就无法利用该对象改变视图层。
Object.freeze()
方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。
freeze()
返回和传入的参数相同的对象。
三、实例生命周期钩子
1. 生命周期
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。
2. 生命周期钩子
可以在创建 Vue 实例时,在参数中填入对应的(生命周期钩子)函数,它会在实例生命周期中的对应阶段被自动调用。
四、插值
1. Mustache
即双大括号
1 |
|
显示时,Mustache 标签将会被替代为对应的数据属性值
当数据属性发生改变时,插值处的内容也会进行更新
双大括号内不仅可以写数据属性,还可以写简单的表达式
1
2
3
4
5
6
7
8<div>{{num * 2}}</div>
var app = new Vue({
el: 'div',
data: {
num: 30,
}
})双大括号可以配合括号之外的文本显示
1
2
3
4
5
6
7
8><div>数字是:{{num * 2}}</div>
>var app = new Vue({
el: 'div',
data: {
num: 30,
}
>})
2. v-once
通过 v-once 指令,能够进行一次性的插值。数据仅会在最开始时进行一次插值,此后都不会再进行更新。
1 |
|
3. v-html
如果需要插值的内容并不是简单的字符串,而是 HTML 代码,则可以通过 v-html 实现。此时,不会再将数据属性解释为普通文本,而是将 数据属性直接替换至 HTML 元素之中。
1 |
|
- HTML 元素中的内容(包括双引号语法)都将被覆盖,因为它们会直接被替代
v-html
应该仅对可信内容使用,如果对未知内容进行 HTML 插值,将可能被恶意攻击
4. v-text
与双引号语法类似,将数据属性解析为文本后替换至 HTML 元素之中。
与 v-html 类似,替换后将覆盖原本的所有内容。
双引号语法相比 v-text 更加灵活
5. v-pre
跳过元素和它的子元素的编译过程,用于输出原始内容。
与 HTML 中的 pre 类似
1 |
|
6. v-cloak
在实际的网页加载过程中,有可能 HTML 已经加载出来,而 JavaScript 还尚未加载。此时网页中就会显示出未经处理的 HTML 内容,并在 JavaScript 成功后出现”闪烁”。例如:
可以通过 v-cloak 和 CSS 样式解决这一问题。
v-cloak:这个属性将被添加在 HTML 中,并在 Vue 实例成功加载后被移除
CSS 样式:可以通过属性选择器选中元素,并将其设置为
display: none
,使它在加载完成之前被隐藏display: none
是官方写法,但个人认为visibility: hidden
更好
1 |
|
五、绑定属性
1. 绑定一般属性
通过 v-bind
动态绑定 HTML 属性值,从而为实现响应式的属性。
(1) 基本写法
语法:
1 |
|
示例:
1 |
|
(2) 语法糖
v-bind:HTML属性="数据属性"
可以简写为 :HTML属性="数据属性"
在绑定
class
或style
时,支持其它类型的值,如数组或对象。并且动态绑定的class/style
能够与普通的class/style
共存。
2. 绑定 class
(1) 基本写法
略
(2) 对象写法
语法:
1 |
|
若布尔值为 true ,则类名会生效;若布尔值为 false,则类名无效。
1:class="{name1: true, name2: false}"
等效于
1class="name1"
通常做法:
为布尔值设置一个 Vue 属性,用于指示类名是否生效。
1 |
|
示例:
1 |
|
(3) 对象+方法
可以通过方法返回类的对象
1 |
|
(4) 数组写法
语法:
1 |
|
通常写法:
不直接写类名(因为直接写类名的话根本没有意义),而是在其中填入数据属性,从而实现响应式类名。
1 |
|
(5) 数组+方法
可以通过方法返回类的数组
1 |
|
3. 绑定 style
(1) 基本写法
略
(2) 对象写法
语法:
1 |
|
通常做法:
设置数据属性,方便根据需要修改 CSS 样式。
1 |
|
示例:
1 |
|
(3) 对象+方法
可以通过方法返回 CSS 的对象
1 |
|
(4) 数组写法
语法:
1 |
|
示例:
1 |
|
六、计算属性
1. 计算属性是什么?
可以理解为对于原有属性进行逻辑运算后的结果。
2. 为什么要用计算属性?
由 Vue 实例如下:
1 |
|
假设需要获得完整的名字,此时有几种做法:
(1) 表达式
1 |
|
这样的做法臃肿且难以维护
(2) 函数
1 |
|
这样的方法相比于表达式的做法更加简洁,但也存在问题:在应填入 数据属性的位置填入方法,略显奇怪
(3) 计算属性
1 |
|
相比于函数的做法:
- 更加简洁
- 计算属性以属性的形式在 HTML 中使用,更加符合习惯
- 计算属性有缓存,可以避免重复计算
3. get 和 set
(1) 计算属性的完整写法
1 |
|
(2) 简写计算属性
set 一般不会使用,因此可以将其留空或省略,还可以直接简写计算属性。
1 |
|
4. 计算属性的缓存
计算属性拥有缓存,它会且仅会在它的相关属性发生改变时才重新求值。因此,在需要多次获得某个“复合值”时,如果通过函数实现,则系统需要进行多次求值;而通过计算属性实现时,系统只会计算一次,并在下一次获取时直接返回计算结果。
在非特殊情况下,尽量使用计算属性,它将能够大大减少性能开销。
七、监听器
1. 什么是监听器?
监听器用于监听数据的变化,当数据变化时,执行对应的方法。
2. 语法
1 |
|
监听器有两个可选参数,其中第一个参数会被传入更新前的数据,第二个参数会被传入更新后的数据。
3. 示例
(1) 打印数据的改变
1 |
|
(2) 防止修改数据
1 |
|
(3) 应用可选参数
1 |
|
4. 监听器的动态注册与注销
(1) 为什么需要动态生成与注销?
有时候,我们不希望监听器始终生效,而是希望它在适当的时候出现,并在适当的时候消失。
(2) 动态注册
可以通过 app.$watch()
方法动态注册监听器,具体语法如下:
1 |
|
(3) 动态注销
调用 app.$watch()
方法时会返回一个 unWatch()
方法,只需要保存它并在适当的时候调用,就可以动态注销监听器。
(4) 示例
有一个数字,它将会随时间 “正常递增”,也可能被用户 “非法篡改”。
我们希望监听它的 “非法篡改”。
代码如下:
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<template>
<div class="home">
<el-input style="width: 300px" v-model="num"></el-input>
<p v-if="isEdit">你进行了编辑</p>
</div>
</template>
<script>
export default {
name: "Test",
data() {
return {
num: 1,
isEdit: false
}
},
mounted() {
setInterval(() => {
this.num++
},2000)
},
watch: {
num() {
this.isEdit = true
}
}
}
</script>
理想状态下,监听器只应该监听 “非法篡改”,而不应该监听 “正常递增”。
但实际情况是,监听器会监听每一个改变,包括 “正常递增”。
此时,我们便可以使用动态注册与注销监听器的方法。
代码如下:
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
<template>
<div class="home">
<el-input style="width: 300px" v-model="num"></el-input>
<p v-if="isEdit">你进行了编辑</p>
</div>
</template>
<script>
export default {
name: "Test",
data() {
return {
num: 1,
isEdit: false,
watch: null
}
},
mounted() {
setInterval(() => {
this.watch && this.watch()
this.num++
this.watch = this.$watch('num', () => {
this.isEdit = true
})
},2000)
}
}
</script>
在 “正常递增” 之前注销监听器,并在 “正常递增” 之后注册监听器,便可以实现我们想要的效果。
八、事件处理
1. 事件监听
可以用 v-on
监听 DOM 事件,当事件触发时执行相应的代码。
(1) 直接嵌入代码
1 |
|
(2) 绑定方法
1 |
|
(3) 调用方法
1 |
|
2. 语法糖
v-on:事件="代码"
可以简写为 @事件="代码"
。
3. 参数
如果方法本身无需传递参数,在监听事件时省略括号,方法将正常执行。
1 |
|
如果方法本身需要传递参数,在监听事件时不传入参数且不省略括号,则参数会被设为 undefined 。
1 |
|
如果方法本身需要传递参数,在监听事件时不传入参数且省略括号,此时 Vue 会将浏览器自动生成的 event 事件对象传入方法。
Event 对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态。
1 |
|
如果需要为方法传入 event 事件,可以使用 $event
将其传入。
1 |
|
4. 修饰符
(1) 语法
1 |
|
(2) .stop
用于阻止事件冒泡。
例如:
1
2
3<div>
<p></p>
</div>点击 p 后事件冒泡,div 也将触发点击事件,这便是事件冒泡。可以通过
.stop
阻止事件冒泡。
(3) .self
仅在事件绑定的元素与触发事件的元素一致时才执行方法。即仅在事件与元素相对应时,才会执行方法。
(4) .capture
正常而言,当事件触发时,从子层开始执行,并逐个向上冒泡。
给元素添加了 .capture 修饰符后,当发生冒泡时,将会首先触发带有 .capture 的元素。若多个元素带有 .capture ,则这些元素由外向内触发。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24<div @click="div">
<h1 @click="h1">
<p @click="p">
<span @click="span">
测试
</span>
</p>
</h1>
</div>
methods: {
div() {
console.log('div')
},
h1() {
console.log('h1')
},
p() {
console.log('p')
},
span() {
console.log('span')
}
}默认情况下,触发顺序为从子层开始执行,逐个向上冒泡:
若设置 .capture,则设置了 .capture 的元素将优先被执行:
1
2
3
4
5
6
7
8
9<div @click="div">
<h1 @click.capture="h1">
<p @click="p">
<span @click="span">
测试
</span>
</p>
</h1>
</div>若同时有多个元素设置了 .capture ,则这些元素由外向内触发。
1
2
3
4
5
6
7
8
9<div @click.capture="div">
<h1 @click.capture="h1">
<p @click="p">
<span @click="span">
测试
</span>
</p>
</h1>
</div>
(5) .prevent
用于阻止默认事件。
例如阻止 submit 默认的提交事件。
(6) .once
事件将只会触发一次。
(7) 按键修饰符
可以通过按键修饰符来使系统只监听特定按键。
1
2<!--只有在enter键被抬起时,才会执行方法-->
<input v-on:keyup.enter="fun">
(8) .native
对于自定义组件,Vue 只会监听通过 $emit
触发的事件,.native 修饰符用于监听组件的原生事件。
例如组件中的 click
5. 为什么在 HTML 中监听事件?
你可能注意到这种事件监听的方式违背了关注点分离 (separation of concern) 这个长期以来的优良传统。但不必担心,因为所有的 Vue.js 事件处理方法和表达式都严格绑定在当前视图的 ViewModel 上,它不会导致任何维护上的困难。实际上,使用
v-on
有几个好处:
- 扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。
- 因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。
- 当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何清理它们。
九、条件渲染
1. v-if
v-if
指令用于根据条件决定是否渲染一块内容。
当
v-if
为 true 时,元素将正常显示当
v-if
为 false 时,元素及其子元素都不会被渲染
1 |
|
2. v-else
v-else
紧跟在 v-if
或者 v-else-if
之后,用于在 v-if
为 false 时显示另一个元素。
1 |
|
3. v-else-if
v-else-if
紧跟在 v-if
或者 v-else-if
之后,类似 else if
。
1 |
|
4. 元素的复用
(1) 元素复用问题
在通过 v-if
进行元素的切换,会发现一个问题:
1 |
|
虽然切换了两个不同的输入框,但输入框中的内容并没有被清除,这在某些情况下是不合理的。这是因为 Vue 进行了元素复用。
(2) Vue 的渲染方式
Vue 为了尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染,通过这样方式使 Vue 更”快”。
(3) 确保被重新渲染
如果需要确保输入框被重新渲染,可以为不同元素添加不同的 key 值。
1 |
|
5. v-show
v-D
指令用于根据条件决定是否显示元素。
当
v-show
为 true 时,元素将正常显示当
v-show
为 false 时,元素及其子元素都不会显示
6. v-if 和 v-show
v-if
决定元素是否被渲染,当条件为假时,元素并不会出现在 DOM 中v-show
仅仅决定元素是否显示v-if
有更高的切换开销,因为每次切换需要进行元素的摧毁与重建v-show
有更高的促使渲染开销,因为它的初始化必定会渲染元素如果需要频繁切换,使用
v-show
如果条件改变较少,使用
v-if
十、列表渲染
1. v-for
(1) 语法
1 |
|
(2) item
item 为元素的别名,可以任意修改,例如 i in items
(3) items
items 为数据来源,
可以是 Vue 实例中的数组、对象、计算属性、方法
可以是数值
1
2
3v-for="n in 10"
遍历 1 ~ 10
2. 遍历数组
元素、索引的别名并不严格要求,可以随意取
(1) 获得元素
1 |
|
(2) 获得元素及索引
1 |
|
3. 遍历对象
属性值、属性名的别名并不严格要求,可以随意取
(1) 获得属性值
1 |
|
(2) 获得属性值和属性名
1 |
|
(3) 获得属性值、属性名及索引
1 |
|
4. :key
建议在使用
v-for
时,给对应元素加上一个:key
属性。
1<li v-for="item in items" :key="item">{{item}}</li>
通过 :key
,可以使 Vue 在进行数据项的更新时,能够更加高效地更新虚拟 DOM 。
5. 数组更新的监听
(1) 响应式的方法
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
这些方法对于数组的改动是响应式的,将会触发视图更新。
(2) 非响应式的改动
通过索引值直接修改元素,将无法触发视图的更新。
解决方法:用
splice(索引, 1, 新元素)
替代
部分方法并不会修改原始数组,而是返回新数组,这种方法也无法触发视图的更新。
解决方法:
数组 = 方法(数组)
,即用新的数组替代原来的数组
6. v-for 和 v-if 配合使用
不推荐在同一元素上使用
v-if
和v-for
(1) 同一节点中
v-if
将重复运行于每一次 v-for
循环中,可以借此来渲染符合条件的元素。
(2) v-if 放置于外层
能够实现通过条件决定是否跳过循环。
十一、双向绑定
1. v-model
v-model
可以在 input、textarea、select 上创建双向绑定。从而能够根据页面输入更新数据,根据数据更新改变页面。
本质上 v-model
是一个语法糖,是属性绑定和事件监听的结合。
v-model
会忽略所有表单元素的value
、checked
、selected
而总是将 Vue 实例的数据作为初始值。
2. v-model 的自适应
v-model
会为不同的元素绑定不同的属性并监听不同的事件,例如:
- text 和 textarea 元素绑定 value 并监听 input 事件
- checkbox 和 radio 绑定 checked 并监听 change 事件
- select 绑定 value 并监听 change 事件
3. 绑定输入框
绑定至字符串,与输入框中输入的内容相对应。
1 |
|
1 |
|
4. 绑定 radio
绑定至字符串,与选中项的 value 相对应。
1 |
|
如果需要默认选中某个选项,可以在 Vue 实例中,将 picked 设为对应选项的 value 。
5. 绑定 checkbox
(1) 单个复选框
绑定至布尔值,与复选框的选中/未选中的状态相对应。
1 |
|
(2) 多个复选框
绑定至数组,数组元素为已选中选项的 value 。
1 |
|
6. 绑定 select
(1) 单选
绑定至字符串,与选中项相对应。
1 |
|
如果
v-model
表达式的初始值未能匹配任何选项,<select>
元素将被渲染为“未选中”状态。在 iOS 中,这会使用户无法选择第一个选项。因为这样的情况下,iOS 不会触发 change 事件。因此,更推荐像上面这样提供一个值为空的禁用选项。
(2) 多选
绑定至数组,数组元素为已选中选项的 value 。
1 |
|
7. 值绑定
即将选项从静态的字符串改成动态绑定的值,从而实现了选项的动态生成和动态修改。
8. 修饰符
(1) .lazy
正常情况下,每次 input 触发时,输入框的值都将与数据进行同步。如果不希望这么”频繁”,便可以通过 .lazy
修饰符解决。它使 v-model
仅在 change
事件触发后才进行同步,具体体现为敲回车或失去焦点时,才进行同步。
(2) .number
用于将用户输入的值自动转换为数值类型。
否则 Vue 会自动将数据转换为字符串类型,即使原本输入的是数值
(3) .trim
自动过滤用户输入的首尾空白字符。
十二、runtime-only 和 runtime-compiler
- runtime-only 运行步骤为:template -> ast -> render -> 虚拟dom ->真实dom
- runtime-compiler 运行步骤为:render -> 虚拟dom ->真实dom
比较而言,runtime-only 运行更快,代码更少,但无法直接解析 Vue 中的 template ,需要由 vue-template-compiler 插件预先进行解析。
Vue-CLI 会帮我们安装并配置