未做特殊说明的,全部都默认为vue3

指令

动态参数

可以在指令参数中使用 JavaScript 表达式,方法是用方括号括起来:

1
<a v-bind:[attributeName='cur']>...</a>

如果组件实例有一个 data property attributeName,其值为 "href",那么这个绑定将等价于 v-bind:href

同样的,也可以使用动态参数作为一个动态的事件名绑定处理函数:

1
<a v-on:[eventName]='doSomething'>...</a>

在这个示例中,当 eventName 的值为 focus 时,v-on:[eventName] 将等价于 v-on:focus

缩写

v-bind缩写

1
2
3
4
5
6
7
8
<!-- 完整语法 -->
<a v-bind:href='url'>...</a>

<!-- 缩写 -->
<a :href='url'>...</a>

<!-- 动态参数缩写 -->
<a :[key]='url'>...</a>

v-on缩写

1
2
3
4
5
6
7
8
<!-- 完整语法 -->
<a v-on:click='doSomething'>...</a>

<!-- 缩写 -->
<a @click='doSomething'>...</a>

<!-- 动态参数的缩写(2.6.0+) -->
<a @[event]='doSomething'>...</a>

动态参数值的约定

动态参数预取会求出一个字符串,异常情况下值为 null ,这个特殊的 null 值可以被显性地用于移除绑定。任何其他非字符串类型的值都将会触发一个警告

动态参数表达式的约定

1
2
<!-- 这会触发一个编译警告 -->
<a v-bind:['foo' + bar]='value'> ... </a>
  • 使用没有空格或引号的表达式,或用计算属性替代复杂表达式
  • 避免使用大写字符来命名键名,因为浏览器会把字符全部强制转换为小写

计算属性和侦听器

计算属性缓存

计算属性只在相关响应式依赖发生改变时他们才会重新求值。这意味着,如果依赖没有发生改变,多次访问计算属性,会立即返回之前的计算结果,而不必再次执行函数

下面的计算属性将不会更新,因为 Date.now() 不是响应式依赖

1
2
3
4
5
computed:{
now(){
return Date.now()
}
}

Class 与 Style 绑定

绑定HTML Class

对象语法

可以传给 :class (v-bind:class的简写) 一个对象,以动态地切换 class

1
<div :class="{ active: isActive }"></div>

上面的语法表示 active 这个 class 存在与否将取决于数据 property isActive 的真假

也可以在对象中传入更多字段来动态切换多个 class。此外,:class 指令也可以与普通的 class 属性共存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div
class='static'
:class="{ active: isActive, 'text-danger': hasError }"
>
</div>

data(){
return {
isActive: true,
hasError: false
}
}

// 渲染结果为:
<div class='static active'></div>

绑定的数据对象不必内联定义在模板里:

1
2
3
4
5
6
7
8
9
10
<div :class='classObject'></div>

data(){
return {
classObject: {
active: true,
text-danger: false
}
}
}

渲染的结果和上面一样。我们也可以在这里绑定一个返回对象的计算属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div :class='classObject'></div>

data() {
return {
isActive: true,
error: null
}
},
computed: {
classObject() {
return {
active: this.isActive && !this.error,
text-danger: this.error && this.error.type === 'fatal'
}
}
}

数组语法

可以把一个数组传给 :class,以应用一个 class 列表

1
2
3
4
5
6
7
8
9
10
11
<div :class='[activeClass, errorClass'></div>

data(){
return {
activeClass: 'active',
errorClass: 'text-danger'
}
}

// 渲染结果为
<div class='active text-danger'></div>

在组件上使用

如果组件有多个根元素,需要定义哪些部分将接受这个类,可以使用 $attrs 组件属性执行此操作:

1
2
3
4
5
6
7
8
9
10
11
12
<div id='app'>
<my-component class='baz'></my-component>
</div>

const app = Vue.createApp({})

app.component('my-component',{
template:`
<p :class='$attrs.class'>Hi!</p>
<span>This is a child component</span>
`
})

条件渲染

v-show

v-show 不支持 <template> 元素

v-if 与 v-for

vue2.0中,v-for 优先级高于 v-if
vue3.0中,v-if 优先级高于 v-for,这意味着 v-if 将没有权限访问 v-for 里的变量

列表渲染

v-for

v-for 里使用对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<ui id='v-for-object' class='demo'>
<li v-for='(value,name,index) in myObject'>
{{index}}.{{name}}:{{value}}
</li>
</ul>

data() {
return {
myObject: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2021-05-21'
}
}
}

// 输出结果:
· 0.title:How to do lists in Vue
· 1.author:Jane Doe
· 2.publishedAt:2021-05-21

在遍历对象时,会按 Object.keys() 的结果遍历,但是不能保证 它在不同 JavaScript 引擎下的结果都一致

v-for 渲染元素列表时,为什么要设置 key ?
vue默认使用‘就地更新’策略。如果数据项的顺序被改变,vue将不会移动DOM元素来匹配数据项的顺序,而是就地更新每个元素,并且确保他们在每个索引位置正确的渲染。
为了给vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,所以需要提供唯一值key

事件处理

内联处理器中的方法

有时需要在内联语句处理器中访问原始的DOM事件。可以用特殊变量 $event 把它传入方法

1
2
3
4
5
6
7
8
9
10
11
12
<button @click="warn('Form cannot be submitted yet.',$event)">
submit
</button>

methods:{
warn(message,event){
if(event){
event.preventDefault()
}
alert(message)
}
}

多事件处理

事件处理程序中可以有多个方法,这些方法由逗号运算符分隔

1
2
3
4
5
6
7
8
9
10
11
12
<button @click='one($event),two()'>
submit
</button>

methods:{
one(event){
// do some thing
},
two(){
// do some thing
}
}

事件修饰符

  • .stop
  • .prevent
  • .capture
  • .self
  • .once
  • .passive
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!-- 阻止事件冒泡 -->
<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>

使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击

.passive
在很多情况下,触摸事件(touchmove、touchstart、touchend……)和鼠标事件会一起触发(以使非触摸专用的代码仍然可以与用户交互)。如果只想使用触摸事件,可以使用 preventDefault() 来取消鼠标事件,即此时 passive 值为 false。将 passive 设置为 true,事件监听(listener)将不会调用 preventDefault() ,如果调用了,将会抛出控制台警告。这样解决了 在处理某些触摸事件的事件监听器在尝试处理滚动时阻止浏览器的主线程的可能性,导致滚动处理期间性能大大降低的问题

按键修饰符

1
2
<!-- 只有在 key 是 Enter 时调用 submit() -->
<input @keyup.enter='submit'>

其他案件别名

  • .enter
  • .tab
  • .delete(捕获 删除 和 退格 键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

系统修饰符

可以用以下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器

  • .ctrl
  • .alt
  • .shift
  • .meta (windows系统键盘上的windows徽标键,Mac上的command键)

.exact修饰符

精确控制系统修饰符触发的事件

1
2
3
4
5
6
7
8
<!-- 无 exaxt 修饰符。即使按住 Alt 或 Shift 的同时按住 ctrl 也会触发 -->
<button @click.ctrl='onClick'>A</button>

<!-- 有 exact 修饰符。只有 Ctrl 被按下的时候才触发 -->
<button @click.ctrl.exact='onClick'>A</button>

<!-- 没有任何按键修饰符被按下的时候才触发 -->
<button @click.exact='onClick'>A</button>

鼠标修饰符

  • .left
  • .right
  • .middle

组件

监听子组件事件

子组件新增 emits ,类似于 props 。可以列出已抛出的事件

props 类似,如果使用对象语法而不是数组语法定义发出的事件,则可以验证它。

要添加验证,将为事件分配一个函数,该函数接受传递给 $emit 调用的参数,并返回一个布尔值以指示事件是否有效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 当在 emits 选项中定义了原生事件(如 click)时,将使用组件中的事件替代原生事件侦听器
app.component('custom-form',{
emits:{
// 不校验
click: null,

// 校验
submit: ({email,password}) => {
if(email && password) {
reutrn true
}
console.warn('Invalid event payLoad!')
return false
}
},
methods:{
submitForm(){
this.$emit('submit', {email,password})
}
}
})

动态组件

效果类似于选项卡,动态切换组件
通过 <component></component> 元素添加一个 is 属性来实现

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
<template>
<div style="padding: 30px">
<button @click="change('1')">组件1</button>
<button @click="change('2')">组件2</button>
<button @click="change('3')">组件3</button>
<!-- 失活的组件将会被缓存 -->
<keep-alive>
<component :is="componentTag"></component>
</keep-alive>
</div>
</template>
<script>
import component1 from './component1'
import component2 from './component2'
import component3 from './component3'
export default {
components: {component1, component2, component3},
data() {
return {
componentTag: '',
}
},
methods: {
change(index) {
this.componentTag = 'component' + index
},
}
}
</script>

异步组件

有时,组件需要从后台获取,可以使用 defineAsyncComponent 方法:

1
2
3
4
5
6
7
8
9
10
11
const app = Vue.createApp({})

const AsyncComp = Vue.defineAsyncComponent(()=>{
new Promise((resolve, reject)=>{
resolve({
template: '<div>I am async!</div>'
})
})
})

app.component('async-example',AsyncComp)

在本地注册组件 时,也可以使用 defineAsyncComponent

1
2
3
components:{
AsyncComponent: defineAsyncComponent(()=>import('./components/AsyncComponent.vue'))
}

异步组件在默认情况下是可挂起的。这意味着如果它在父链中有一个 <Suspense> ,它将被视为该 <Suspense> 的异步依赖。这种情况下,加载状态将由 <Suspense> 控制,组件自身的加载、错误、延迟和超时选项将被忽略

异步组件也可以选择退出 <Suspense> 控制,并通过在其选项中指定 suspensable:false , 让组件始终控制自己的加载状态