Appearance
Vue3 基础 P1
生命周期

Note:Vue3 和 Vue2 的生命周期钩子函数在名称上有一些区别:
beforeUnmount、unmounted对应 Vue2 中的beforeDestroy、destroyed。
注册周期钩子
举例来说,onMounted 钩子可以用来在组件完成初始渲染并创建 DOM 节点后运行代码:
HTML
<script setup>
import { onMounted } from 'vue'
onMounted(() => {
console.log(`the component is now mounted.`)
})
</script>1
2
3
4
5
6
7
2
3
4
5
6
7
还有其他一些钩子,会在实例生命周期的不同阶段被调用,最常用的是 onMounted、onUpdated 和 onUnmounted。所有生命周期钩子的完整参考及其用法请参考 API 索引。
当调用 onMounted 时,Vue 会自动将回调函数注册到当前正被初始化的组件实例上。这意味着这些钩子应当在组件初始化时被同步注册。例如,请不要这样做:
JavaScript
setTimeout(() => {
onMounted(() => {
// 异步注册时当前组件实例已丢失
// 这将不会正常工作
})
}, 100)1
2
3
4
5
6
2
3
4
5
6
注意这并不意味着对 onMounted 的调用必须放在 setup() 或 <script setup> 内的词法上下文中。onMounted() 也可以在一个外部函数中调用,只要调用栈是同步的,且最终起源自 setup() 就可以。
模板语法
插值
文本
HTML
<span>Message: {{ msg }}</span>一次性插值:
HTML
<span v-once>这个将不会改变: {{ msg }}</span>原始 HTML
CSS:
CSS
.demo {
font-family: sans-serif;
border: 1px solid #eee;
border-radius: 2px;
padding: 20px 30px;
margin-top: 1em;
margin-bottom: 40px;
user-select: none;
overflow-x: auto;
}1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
HTML:
HTML
<div id="container" class="demo">
<p>Using mustaches: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
</div>1
2
3
4
2
3
4
JavaScript:
JavaScript
const opt = {
data: function () {
return {
rawHtml: '<i style="color: red">This should be red.</i>'
}
}
}
Vue.createApp(opt).mount('#container')1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
输出:
HTML
<div id="container" class="demo" data-v-app="">
<p>Using mustaches: <i style="color: red">This should be red.</i></p>
<p>Using v-html directive: <span><i style="color: red">This should be red.</i></span></p>
</div>1
2
3
4
2
3
4
span 的内容将会被替换为 rawHtml 属性的值,插值为纯 HTML —— 数据绑定将会被忽略。注意,你不能使用 v-html 来拼接组合模板,因为 Vue 不是一个基于字符串的模板引擎。在使用 Vue 时,应当使用组件作为 UI 重用和组合的基本单元。
Attribute
HTML
<div v-bind:id="dynamicId"></div>如果绑定的值是 null 或 undefined,那么该 Attribute 将不会被包含在渲染的元素上。
布尔型 Attribute
对于布尔 Attribute(它们只要存在就意味着值为 true),如:
HTML
<button v-bind:disabled="isButtonDisabled">按钮</button>如果 isButtonDisabled 的值是真值,那么 disabled Attribute 将被包含在内(需要注意的是如该值是一个空字符串,它也会被包括在内,与 <button disabled=""> 保持一致)。对于其他假值 的值,该 Attribute 将被省略。
动态绑定多个值
如果你有像这样的一个包含多个 Attribute 的 JavaScript 对象:
JavaScript
const objectOfAttrs = {
id: 'container',
class: 'wrapper',
style: 'background-color:green'
}1
2
3
4
5
2
3
4
5
通过不带参数的 v-bind,你可以将它们绑定到单个元素上:
Java
<div v-bind="objectOfAttrs"></div>JavaScript 表达式
HTML
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div v-bind:id="`list-${id}`"></div>1
2
3
4
5
6
7
2
3
4
5
6
7
以上表达式会在当前活动实例的数据作用域下作为 JavaScript 被解析,但每个绑定都只能包含单个表达式。
Note:模板表达式都被放在沙盒中,只能访问一个受限的全局变量列表,如
Math和Date。你不应该在模板表达式中试图访问用户定义的全局变量(例如用户附加在window上的属性)。然而,你也可以自行在app.config.globalProperties上显式地添加它们,供所有的 Vue 表达式使用。
指令
指令 Attribute 的值预期是单个 JavaScript 表达式(v-for、v-on 和 v-slot 例外)。
HTML
<p v-if="seen">现在你看到我了</p>v-if 指令将根据表达式 seen 的值的真假来插入/移除 <p> 元素。
完整的指令语法:

参数
一些指令能够接收一个 “参数”,在指令名称之后以冒号表示。
例如:
v-bind指令用于响应式地更新 HTML Attribute:HTML<a v-bind:href="url"> ... </a>在这里
href是参数,告知v-bind指令将该元素的hrefAttribute 与表达式url的值绑定。v-on指令用于监听 DOM 事件:HTML<a v-on:click="doSomething"> ... </a>在这里
click是参数。
动态参数
也可以在指令参数中使用 JavaScript 表达式,方法是用方括号括起来:
HTML
<a v-bind:[attributeName]="url"> ... </a>这里的 attributeName 会被作为一个 JavaScript 表达式进行动态求值,求得的值将会作为最终的参数来使用。例如,如果你的组件实例有一个数据属性 attributeName,其值为 "href",那么这个绑定将等价于 v-bind:href。
Note
当动态参数值为
null时可以用于显式地移除绑定;在使用动态参数表达式时需要注意:
某些字符,如空格和引号,放在 HTML Attribute 名里是无效的:
HTML<!-- 这会触发一个编译警告 --> <a v-bind:['foo' + bar]="value"> ... </a>1
2解决方式是,可以使用计算属性替代这种复杂表达式。
需要避免使用大写字符来命名键名(因为浏览器会把 Attribute 名全部强制转为小写):
HTML<!-- 在 DOM 中使用模板时这段代码会被转换为 `v-bind:[someattr]`。 除非在实例中有一个名为 “someattr” 的 property,否则代码不会工作。 --> <a v-bind:[someAttr]="value"> ... </a>1
2
3
4
5单文件组件内的模板不受此限制。
修饰符
修饰符(Modifier)是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。例如,.prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault():
HTML
<form v-on:submit.prevent="onSubmit">...</form>缩写
Vue 为 v-bind 和 v-on 这两个最常用的指令,提供了特定简写:
v-bindHTML<!-- 完整语法 --> <a v-bind:href="url"> ... </a> <!-- 缩写 --> <a :href="url"> ... </a> <!-- 与 :href="href" 相同 --> <a :href> ... </a> <!-- 动态参数的缩写 --> <a :[key]="url"> ... </a>1
2
3
4
5
6
7
8
9
10
11v-onHTML<!-- 完整语法 --> <a v-on:click="doSomething"> ... </a> <!-- 缩写 --> <a @click="doSomething"> ... </a> <!-- 动态参数的缩写 --> <a @[event]="doSomething"> ... </a>1
2
3
4
5
6
7
8
Class 与 Style 绑定
因为 Class 与 Style 都是 Attribute 所以我们可以直接用 v-bind 处理它们,只需要通过表达式计算出字符串结果即可。
不过在将 v-bind 用于 class 和 style 时 Vue 实际上还专门做了增强,表达式结果的类型还支持对象或数组。
绑定 HTML Class
对象语法
定义在模板中:
HTML
<!-- :class 指令也可以与普通的 class attribute 共存 -->
<div class="static" :class="{ active: isActive, 'text-danger': hasError }"></div>1
2
2
JavaScript
data() {
return {
isActive: true,
hasError: false
}
}1
2
3
4
5
6
2
3
4
5
6
输出:
HTML
<!-- 如果 hasError 的值为 true,class 列表将变为 "static active text-danger" -->
<div class="static active"></div>1
2
2
定义在属性中:
绑定的数据对象也可以不必内联定义在模板里:
HTML
<div :class="classObject"></div>JavaScript
data() {
return {
classObject: {
active: true,
'text-danger': false
}
}
}1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
使用计算属性:
也可以在这里绑定一个返回对象的计算属性:
HTML
<div :class="classObject"></div>JavaScript
data() {
return {
isActive: true,
error: null
}
},
computed: {
classObject() {
return {
active: this.isActive && !this.error,
'text-danger': this.error && this.error.type === 'fatal'
}
}
}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
数组语法
HTML
<div :class="[activeClass, errorClass]"></div>JavaScript
data() {
return {
activeClass: 'active',
errorClass: 'text-danger'
}
}1
2
3
4
5
6
2
3
4
5
6
输出:
HTML
<div class="active text-danger"></div>还可以结合使用三元表达式:
HTML
<div :class="[isActive ? activeClass : '', errorClass]"></div>甚至结合使用对象语法:
HTML
<div :class="[{ active: isActive }, errorClass]"></div>在组件上使用
对于只有一个根元素的组件,当你使用了 class Attribute 时,这些 class 会被添加到根元素上并与该元素上已有的 class 合并。
举例来说,如果你声明了一个组件名叫 MyComponent,模板如下:
HTML
<!-- 子组件模板 -->
<p class="foo bar">Hi!</p>1
2
2
在使用时添加一些 class:
HTML
<!-- 在使用组件时 -->
<MyComponent class="baz boo" />1
2
2
渲染出的 HTML 为:
HTML
<p class="foo bar baz boo">Hi!</p>Class 的绑定也是同样的:
HTML
<MyComponent :class="{ active: isActive }" />当 isActive 为真时,被渲染的 HTML 会是:
HTML
<p class="foo bar active">Hi!</p>如果你的组件有多个根元素,你将需要指定哪个根元素来接收这个 class。你可以通过组件的 $attrs 属性来指定接收的元素:
HTML
<!-- MyComponent 模板使用 $attrs 时 -->
<p :class="$attrs.class">Hi!</p>
<span>This is a child component</span>1
2
3
2
3
HTML
<MyComponent class="baz" />这将被渲染为:
HTML
<p class="baz">Hi!</p>
<span>This is a child component</span>1
2
2
你可以在透传 Attribute 一章中了解更多组件的 Attribute 继承的细节。
绑定内联样式
对象语法
:style 的对象语法十分直观 —— 看着非常像 CSS,但其实是一个 JavaScript 对象。CSS Property 名可以用驼峰式(camelCase)或短横线分隔(kebab-case,记得用引号括起来)来命名:
定义在模板中:
HTML
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>JavaScript
data() {
return {
activeColor: 'red',
fontSize: 30
}
}1
2
3
4
5
6
2
3
4
5
6
定义在属性中:
HTML
<div :style="styleObject"></div>JavaScript
data() {
return {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
}1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
使用计算属性:
HTML
<div :style="styleObject"></div>JavaScript
data() {
return {
theme: 'light',
enlargedView: true
}
},
computed: {
styleObject() {
return {
color: this.theme == 'light' ? 'black' : 'white',
fontSize: this.enlargedView ? '20px' : '13px'
}
}
}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
数组语法
HTML
<div :style="[baseStyles, overridingStyles]"></div>浏览器引擎前缀
当在 :style 中使用需要一个 vendor prefix(浏览器引擎前缀)的 CSS Property 时,Vue 将自动侦测并添加相应的前缀。Vue 是通过运行时检测来确定哪些样式的 Property 是被当前浏览器支持的。如果浏览器不支持某个 Property,Vue 会进行多次测试以找到支持它的前缀。
多重值
HTML
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>这样写只会渲染数组中最后一个被浏览器支持的值。在本例中,如果浏览器支持不带浏览器前缀的 Flexbox,那么就只会渲染 display: flex。
条件渲染
v-if
HTML
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
v-else、v-else-if 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。
在需要切换多个元素的时候,可以把一个 <template> 元素当做不可见的包裹元素,并在上面使用 v-if。最终的渲染结果将不包含 <template> 元素。
HTML
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>1
2
3
4
5
2
3
4
5
v-show
HTML
<h1 v-show="ok">Hello!</h1>与 v-if 不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 display CSS Property。
Note:
v-show不支持<template>元素,也不支持v-else。
v-if vs v-show
v-if 是 “真正” 的条件渲染,因为它会确保在切换过程中,条件块内的事件监听器和子组件适当地被销毁和重建。
一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
列表渲染
根据数组进行渲染
基础示例:
HTML
<ul id="array-rendering">
<li v-for="item in items">
{{ item.message }}
</li>
</ul>1
2
3
4
5
2
3
4
5
JavaScript
Vue.createApp({
data() {
return {
items: [{ message: 'Foo' }, { message: 'Bar' }]
}
}
}).mount('#array-rendering')1
2
3
4
5
6
7
2
3
4
5
6
7
在 v-for 块中,我们可以访问所有父作用域的 Property。v-for 还支持一个可选的第二个参数,即当前项的索引。
HTML
<ul id="array-with-index">
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>1
2
3
4
5
2
3
4
5
JavaScript
Vue.createApp({
data() {
return {
parentMessage: 'Parent',
items: [{ message: 'Foo' }, { message: 'Bar' }]
}
}
}).mount('#array-with-index')1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
你也可以用 of 替代 in 作为分隔符,因为它更接近 JavaScript 迭代器的语法:
HTML
<div v-for="item of items"></div>根据对象进行渲染
HTML
<ul id="v-for-object" class="demo">
<li v-for="value in myObject">
{{ value }}
</li>
</ul>1
2
3
4
5
2
3
4
5
JavaScript
Vue.createApp({
data() {
return {
myObject: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
}
}).mount('#v-for-object')1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
也可以访问 Property 名称(也就是键名 key):
HTML
<li v-for="(value, key) in myObject">
{{ key }}: {{ value }}
</li>1
2
3
2
3
还可以用第三个参数作为索引:
HTML
<li v-for="(value, key, index) in myObject">
{{ index }}. {{ key }}: {{ value }}
</li>1
2
3
2
3
Note:在遍历对象时,遍历的顺序会基于对该对象调用
Object.values()的返回值来决定。
维护状态
默认使用 “就地更新” 的策略,如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态(例如:表单输入值)的列表渲染输出。
为了 Vue 便于跟踪每个节点的身份,从而重用和重新排序现有元素 I,你需要为每项提供一个唯一的 key Attribute:
HTML
<div v-for="item in items" :key="item.id">
<!-- 内容 -->
</div>1
2
3
2
3
当你使用 <template v-for> 时,key 应该被放置在这个 <template> 容器上:
HTML
<template v-for="todo in todos" :key="todo.name">
<li>{{ todo.name }}</li>
</template>1
2
3
2
3
推荐在任何可行的时候为 v-for 提供一个 key Attribute,除非所迭代的 DOM 内容非常简单(例如:不包含组件或有状态的 DOM 元素),或者你想有意采用默认行为来提高性能。
key 绑定的值期望是一个基础类型的值,例如字符串或 number 类型。不要用对象作为 v-for 的 key。关于 key Attribute 的更多用途细节,请参阅 key API 文档。
数组更新检测
变更方法
Vue 能够侦听响应式数组的变更方法,并在它们被调用时触发相关的更新。这些变更方法包括:
push()pop()shift()unshift()splice()sort()reverse()- ...
替换一个数组
变更方法,顾名思义,就是会对调用它们的原数组进行变更。相对地,也有一些不可变 (Immutable) 方法,例如 filter()、concat() 和 slice(),这些都不会更改原数组,而总是返回一个新数组。当遇到的是非变更方法时,我们需要将旧的数组替换为新的:
JavaScript
// `items` 是一个数组的 ref
items.value = items.value.filter((item) => item.message.match(/Foo/))1
2
2
你可能认为这将导致 Vue 丢弃现有的 DOM 并重新渲染整个列表 —— 幸运的是,情况并非如此。Vue 实现了一些巧妙的方法来最大化对 DOM 元素的重用,因此用另一个包含部分重叠对象的数组来做替换,仍会是一种非常高效的操作。
显示过滤/排序后的结果
有时,我们想要显示一个数组经过过滤或排序后的版本,而不实际变更或重置原始数据。在这种情况下,可以创建一个计算属性,来返回过滤或排序后的数组。
HTML
<li v-for="n in evenNumbers" :key="n">{{ n }}</li>JavaScript
data() {
return {
numbers: [ 1, 2, 3, 4, 5 ]
}
},
computed: {
evenNumbers() {
return this.numbers.filter(number => number % 2 === 0)
}
}1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
在计算属性不适用的情况下(例如,在嵌套的 v-for 循环中),还可以使用方法:
HTML
<ul v-for="numbers in sets">
<li v-for="n in even(numbers)" :key="n">{{ n }}</li>
</ul>1
2
3
2
3
JavaScript
data() {
return {
sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]]
}
},
methods: {
even(numbers) {
return numbers.filter(number => number % 2 === 0)
}
}1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
在 v-for 里使用值的范围
v-for 可以直接接受一个整数值。在这种用例中,会将该模板基于 1...n 的取值范围重复多次。
HTML
<div id="range" class="demo">
<span v-for="n in 10" :key="n">{{ n }} </span>
</div>1
2
3
2
3
注意此处 n 的初值是从 1 开始而非 0。
在 <template> 中使用 v-for
类似于 v-if,你也可以利用带有 v-for 的 <template> 来循环渲染一段包含多个元素的内容。比如:
HTML
<ul>
<template v-for="item in items" :key="item.msg">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>1
2
3
4
5
6
2
3
4
5
6
v-for 与 v-if 一同使用
永远不要在一个元素上同时使用 v-if 和 v-for。
一般我们在两种常见的情况下会倾向于这样做:
为了对列表中的项目进行过滤(比如
v-for="user in users" v-if="user.isActive")。在这种情形下,请将users替换为一个计算属性(比如activeUsers),返回过滤后的列表;为了避免渲染本应该被隐藏的列表(比如
v-for="user in users" v-if="shouldShowUsers")。这种情形下,请将v-if移动至容器元素上(比如ul、ol);
实际上,v-if 比 v-for 具有更高的优先级,所以这个模板:
HTML
<ul>
<li
v-for="user in users"
v-if="user.isActive"
:key="user.id"
>
{{ user.name }}
</li>
</ul>1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
将抛出一个错误,因为 v-if 指令将首先被执行,而迭代的变量 user 此时还不存在。
这可以通过遍历一个计算属性来解决,像这样:
JavaScript
computed: {
activeUsers() {
return this.users.filter(user => user.isActive)
}
}1
2
3
4
5
2
3
4
5
HTML
<ul>
<li
v-for="user in activeUsers"
:key="user.id"
>
{{ user.name }}
</li>
</ul>1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
另外,我们也可以使用 <template> 标签和 v-for 来包裹 <li> 元素。
HTML
<ul>
<template v-for="user in users" :key="user.id">
<li v-if="user.isActive">
{{ user.name }}
</li>
</template>
</ul>1
2
3
4
5
6
7
2
3
4
5
6
7
事件处理
我们可以使用 v-on 指令(通常缩写为 @ 符号)来监听 DOM 事件,并在触发事件时执行一些 JavaScript。用法为 v-on:click="methodName" 或使用快捷方式 @click="methodName"。
方法事件处理器
可以通过 v-on 绑定方法名称:
HTML
<div id="event-with-method">
<!-- `greet` 是在下面定义的方法名 -->
<button @click="greet">Greet</button>
</div>1
2
3
4
2
3
4
JavaScript
Vue.createApp({
data() {
return {
name: 'Vue.js'
}
},
methods: {
greet(event) {
// `methods` 内部的 `this` 指向当前活动实例
alert('Hello ' + this.name + '!')
// `event` 是原生 DOM event
if (event) {
alert(event.target.tagName)
}
}
}
}).mount('#event-with-method')1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
内联事件处理器
可以在内联 JavaScript 语句中调用方法:
HTML
<div id="inline-handler">
<button @click="say('hi')">Say hi</button>
<button @click="say('what')">Say what</button>
</div>1
2
3
4
2
3
4
JavaScript
Vue.createApp({
methods: {
say(message) {
alert(message)
}
}
}).mount('#inline-handler')1
2
3
4
5
6
7
2
3
4
5
6
7
如果需要在内联语句处理器中访问原始的 DOM 事件,可以用特殊变量 $event 把它传入方法:
HTML
<button @click="warn('Form cannot be submitted yet.', $event)">
Submit
</button>1
2
3
2
3
JavaScript
// ...
methods: {
warn(message, event) {
// 现在可以访问到原生事件
if (event) {
event.preventDefault()
}
alert(message)
}
}1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
或者使用内联箭头函数:
HTML
<button @click="(event) => warn('Form cannot be submitted yet.', event)">
Submit
</button>1
2
3
2
3
事件处理程序中可以有多个方法,这些方法由逗号运算符分隔:
HTML
<!-- 这两个 one() 和 two() 将执行按钮点击事件 -->
<button @click="one($event), two($event)">
Submit
</button>1
2
3
4
2
3
4
JavaScript
// ...
methods: {
one(event) {
// 第一个事件处理器逻辑...
},
two(event) {
// 第二个事件处理器逻辑...
}
}1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
方法与内联事件判断
模板编译器会通过检查 v-on 的值是否是合法的 JavaScript 标识符或属性访问路径来断定是何种形式的事件处理器。举例来说,foo、foo.bar 和 foo['bar'] 会被视为方法事件处理器,而 foo() 和 count++ 会被视为内联事件处理器。
事件修饰符
.stop:阻止事件继续冒泡.prevent:相当于调用 Event 的preventDefault()方法.capture:添加事件监听器时使用事件捕获模式.self:只当在event.target是当前元素自身时触发处理函数.once:事件将只会触发一次.passive:addEventListener中的passive选项(经常被用于提升移动端的性能)
HTML
<!-- 阻止单击事件继续冒泡 -->
<a @click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form @submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a @click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form @submit.prevent></form>
<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div @click.capture="doThis">...</div>
<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div @click.self="doThat">...</div>
<!-- 点击事件将只会触发一次 -->
<a @click.once="doThis"></a>
<!-- 滚动事件的默认行为(即滚动行为)将会立即触发, -->
<!-- 而不会等待 `onScroll` 完成, -->
<!-- 以防止其中包含 `event.preventDefault()` 的情况 -->
<div @scroll.passive="onScroll">...</div>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
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
Note:使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用
@click.prevent.self会阻止元素本身及其子元素的点击的默认行为,而@click.self.prevent只会阻止对元素自身的点击的默认行为。
按键修饰符
HTML
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input @keyup.enter="submit" />1
2
2
可以直接将 KeyboardEvent.key 暴露的任意有效按键名转换为 kebab-case 来作为修饰符。
HTML
<input @keyup.page-down="onPageDown" />按键别名
Vue 为最常用的键提供了别名:
.enter.tab.delete(捕获 “删除” 和 “退格” 键).esc.space.up.down.left.right
系统修饰键
可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器:
.ctrl.alt.shift.meta
HTML
<!-- Alt + Enter -->
<input @keyup.alt.enter="clear" />
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>1
2
3
4
5
2
3
4
5
.exact 修饰符
.exact 修饰符允许你控制由精确的系统修饰符组合触发的事件:
HTML
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button @click.ctrl="onClick">A</button>
<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>
<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button @click.exact="onClick">A</button>1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
鼠标按钮修饰符
.left.right.middle
这些修饰符会限制处理函数仅响应特定的鼠标按钮。
表单输入绑定
基础用法
可以用 v-model 指令在表单 <input>、<textarea> 及 <select> 元素上创建双向数据绑定。
Note:
v-model会忽略所有表单元素的value、checked、selectedAttribute 的初始值。它将始终将当前活动实例的数据作为数据来源。你应该通过 JavaScript 在组件的data选项中声明初始值。
v-model 它会根据所使用的元素自动使用对应的 DOM 属性和事件组合:
text和textarea元素使用valueProperty 和input事件checkbox和radio使用checkedProperty 和change事件select使用valueProperty 和change事件
Note:对于需要使用输入法(如中文、日文、韩文等)的语言,你会发现
v-model不会在输入法组织文字过程中得到更新。如果你也想响应这些更新,请使用input事件监听器和value绑定来替代v-model。
文本 (Text)
HTML
<input v-model="message" placeholder="edit me" />
<p>Message is: {{ message }}</p>1
2
2
多行文本 (Textarea)
需要注意,插值在 textarea 中不起作用,请使用 v-model 来代替。
HTML
<!-- bad -->
<textarea>{{ text }}</textarea>
<!-- good -->
<textarea v-model="text"></textarea>1
2
3
4
5
2
3
4
5
复选框 (Checkbox)
单复选框:
HTML
<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>1
2
2
多复选框:
HTML
<div id="v-model-multiple-checkboxes">
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames" />
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames" />
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames" />
<label for="mike">Mike</label>
<br>
<span>Checked names: {{ checkedNames }}</span>
</div>1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
JavaScript
Vue.createApp({
data() {
return {
checkedNames: []
}
}
}).mount('#v-model-multiple-checkboxes')1
2
3
4
5
6
7
2
3
4
5
6
7
绑定到指定值(而不是布尔值):
HTML
<input
type="checkbox"
v-model="toggle"
true-value="yes"
false-value="no" />1
2
3
4
5
2
3
4
5
true-value 和 false-value 是 Vue 特有的 Attributes,仅支持和 v-model 配套使用。这里 toggle 属性的值会在选中时被设为 'yes',取消选择时设为 'no'。
true-value 和 false-value Attributes 不会影响 value Attribute,因为浏览器在表单提交时,并不会包含未选择的复选框。为了保证这两个值(例如:yes 和 no)的其中之一被表单提交,请使用单选按钮作为替代。
true-value 和 false-value 同样也支持绑定到动态数据。
单选框 (Radio)
HTML
<div id="v-model-radiobutton">
<input type="radio" id="one" value="One" v-model="picked" />
<label for="one">One</label>
<br>
<input type="radio" id="two" value="Two" v-model="picked" />
<label for="two">Two</label>
<br>
<span>Picked: {{ picked }}</span>
</div>1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
JavaScript
Vue.createApp({
data() {
return {
picked: ''
}
}
}).mount('#v-model-radiobutton')1
2
3
4
5
6
7
2
3
4
5
6
7
选择框 (Select)
单选模式:
HTML
<div id="v-model-select" class="demo">
<select v-model="selected">
<option disabled value="">Please select one</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
</div>1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
JavaScript
Vue.createApp({
data() {
return {
selected: ''
}
}
}).mount('#v-model-select')1
2
3
4
5
6
7
2
3
4
5
6
7
Note:如果
v-model表达式的初始值未能匹配任何选项,<select>元素将被渲染为 “未选中” 状态。在 iOS 中,这会使用户无法选择第一个选项。因为这样的情况下,iOS 不会触发change事件。因此,更推荐像上面这样提供一个值为空的禁用选项。
多选模式(绑定到一个数组):
HTML
<select v-model="selected" multiple>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<br>
<span>Selected: {{ selected }}</span>1
2
3
4
5
6
7
2
3
4
5
6
7
结合 v-for 渲染的动态选项:
HTML
<div id="v-model-select-dynamic" class="demo">
<select v-model="selected">
<option v-for="option in options" :value="option.value">
{{ option.text }}
</option>
</select>
<span>Selected: {{ selected }}</span>
</div>1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
JavaScript
Vue.createApp({
data() {
return {
selected: 'A',
options: [
{ text: 'One', value: 'A' },
{ text: 'Two', value: 'B' },
{ text: 'Three', value: 'C' }
]
}
}
}).mount('#v-model-select-dynamic')1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
绑定到动态数据
绑定的值也可以是一个对象:
HTML
<select v-model="selected">
<!-- 内联对象字面量 -->
<option :value="{ number: 123 }">123</option>
</select>1
2
3
4
2
3
4
JavaScript
// 当选中时
typeof vm.selected // => 'object'
vm.selected.number // => 1231
2
3
2
3
修饰符
.lazy
在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步(除了输入法组织文字时)。可以添加 lazy 修饰符,从而转为在 change 事件之后进行同步:
HTML
<!-- 在 “change” 时而非 “input” 时更新 -->
<input v-model.lazy="msg" />1
2
2
.number
如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符:
HTML
<input v-model.number="age" type="text" />当输入类型为 text 时这通常很有用。如果输入类型是 number,Vue 能够自动将原始字符串转换为数字,无需为 v-model 添加 .number 修饰符。如果这个值无法被 parseFloat() 解析,则返回原始的值。
.trim
如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:
HTML
<input v-model.trim="msg" />