Vue 3 备忘录
以下内容是基于 Vue 官方文档 梳理的备忘录.
模板语法
Attribute 绑定
同名简写
如果 attribute 的名称与绑定的 JavaScript 值的名称相同,那么可以省略 attribute 值:
<template>
<div :id></div>
<!-- 等同于 -->
<div :id="id"></div>
</template>
<script setup>
const id = ref("value");
</script>
动态绑定多个值
<template>
<!-- 通过不带参数的 `v-bind`,你可以将它们绑定到单个元素上: -->
<div v-bind="objectOfAttrs"></div>
</template>
<script setup>
const objectOfAttrs = {
id: "container",
class: "wrapper",
style: "background-color:green"
};
</script>
使用 JavaScript 表达式
Vue 模版中的数据绑定支持完整的 JavaScript 表达式 受限的全局访问 同时模板中的表达式将被沙盒化,仅能够访问到有限的全局对象列表:
const GLOBALS_ALLOWED =
"Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI," +
"decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array," +
"Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,console,Error,Symbol";
没有显式包含在列表中的全局对象将不能在模板内表达式中访问,例如用户附加在 window
上的属性。然而,你也可以自行在 app.config.globalProperties
上显式地添加它们,供所有的 Vue 表达式使用。
全局属性
类型
interface AppConfig {
globalProperties: Record<string, any>;
}
app.config.globalProperties
用于注册能够被应用内所有组件实例访问到的全局属性的对象, 这是对 Vue 2 中 Vue.prototype
使用方式的一种替代,此写法在 Vue 3 已经不存在了。如果全局属性与组件自己的属性冲突,组件自己的属性将具有更高的优先级。
用法
// 定义
app.config.globalProperties.msg = "hello"; // 这使得 msg 在应用的任意组件模板上都可用,并且也可以通过任意组件实例的 this 访问到
// 使用
export default {
mounted() {
console.log(this.msg); // 'hello'
}
};
参数 Arguments
<a v-bind:href="url"> ... </a>
中 href
就是一个参数,它告诉 v-bind
指令将表达式 url
的值绑定到元素的 href
attribute 上, 另一个例子是 v-on
指令: <a v-on:click="doSomething"> ... </a>
这里 click
就是参数, 表示要监听的事件名称.
动态参数
指令参数上也可以使用一个 JavaScript 表达式,需要包含在一对方括号内
<!-- 示例1 -->
<a v-bind:[attributeName]="url"> ... </a>
<!-- 简写 -->
<a :[attributeName]="url"> ... </a>
<!-- 示例2 -->
<a v-on:[eventName]="doSomething"> ... </a>
<!-- 简写 -->
<a @[eventName]="doSomething"> ... </a>
动态参数中表达式的值应当是一个字符串,或者是 null
。特殊值 null
意为显式移除该绑定。其他非字符串的值会触发警告。推荐使用计算属性替换复杂的表达式.
指令、参数、修饰符
以下是 Vue 内置指令(directive):
v-bind
简写:
, 用于绑定值v-on
简写@
, 用于监听事件v-html
用于设置 html 内容
而指令的参数(argument)位于冒号后面, 比如 v-bind:href
中的 href
或者 v-on:click
中的 click
,
修饰符(modfier)用.
分割, 比如 v-on:submit.prevent
中的 prevent
.
响应式基础
浅层响应性
可以通过 shallowRef<T>(value: T)
来放弃深层响应性。对于浅层 shallowRef
,只有 .value
的访问会被追踪, 可以避免对大型数据的响应性开销来优化性能、或者有外部库管理其内部状态的情况。
reactive()
的局限性
- 有限的值类型 它只能用于对象类型 (对象、数组和如 Map、Set 这样的集合类型)。它不能持有如 string、number 或 boolean 这样的原始类型。
- 不能替换整个对象 由于 Vue 的响应式跟踪是通过属性访问实现的,因此我们必须始终保持对响应式对象的相同引用。这意味着我们不能轻易地“替换”响应式对象,因为这样的话与第一个引用的响应性连接将丢失
- 对解构操作不友好 我们将响应式对象的原始类型属性解构为本地变量时,或者将该属性传递给函数时,我们将丢失响应性连接
let state = reactive({count: 0});
// 上面的 ({ count: 0 }) 引用将不再被追踪
// (响应性连接已丢失!)
state = reactive({count: 1});
const state = reactive({count: 0});
// 当解构时,count 已经与 state.count 断开连接
let {count} = state;
// 不会影响原始的 state
count++;
// 该函数接收到的是一个普通的数字
// 并且无法追踪 state.count 的变化
// 我们必须传入整个对象以保持响应性
callSomeFunction(state.count);
计算属性
可写计算属性
计算属性默认是只读的: const fullName = computed((previousValue) => firstName.value + ' ' + lastName.value)
, 可以通过同时提供 getter 和 setter 来创建可读写的计算属性:
import {ref, computed} from "vue";
const firstName = ref("John");
const lastName = ref("Doe");
const fullName = computed({
// getter
get(previousValue) {
return firstName.value + " " + lastName.value;
},
// setter
set(newValue) {
// 注意:我们这里使用的是解构赋值语法
[firstName.value, lastName.value] = newValue.split(" ");
}
});
搭配 defineModel
使用示例:
const modelValue = defineModel<string>({default: ""});
// 内部状态,使用计算属性处理受控的值
const code = computed({
get: previousValue => modelValue.value,
set: newVal => {
const newCode = (newVal || "").substring(0, props.maxLength);
modelValue.value = newCode;
}
});
如果需要,可以通过访问计算属性的 getter
的第一个参数来获取计算属性返回的上一个值(previousValue
)
Class 与 Style 绑定
<!-- 支持绑定字符串 -->
<div :style="'color: red'"></div>
<div :class="'mx-2 active'"></div>
<!-- 支持绑定对象 -->
<div :style="{ color: 'red' }"></div>
<div :class="{ active: isActive }"></div>
<!-- 或者绑定数组 -->
<div :style="[{ color: 'red' }, { backgroundColor: "white" }]"></div>
<div :class="[isActive ? activeClass : '', errorClass]"></div>
<!-- 或者在数组中嵌套对象 -->
<div :class="[{ [activeClass]: isActive }, errorClass]"></div>
在组件上使用
对于只有一个根元素的组件,当你使用了 class attribute 时,这些 class 会被添加到根元素上并与该元素上已有的 class 合并。
<!-- 子组件模板 -->
<p class="foo bar">Hi!</p>
<!-- 在使用组件时 -->
<MyComponent class="baz boo" />
<!-- 最终渲染出的结果: -->
<p class="foo bar baz boo">Hi!</p>
如果你的组件有多个根元素,你将需要指定哪个根元素来接收这个 class。你可以通过组件的 $attrs
属性来指定接收的元素:
<!-- MyComponent 模板使用 $attrs 时 -->
<p :class="$attrs.class">Hi!</p>
<span>This is a child component</span>
<!-- 这将被渲染为: -->
<p class="baz">Hi!</p>
<span>This is a child component</span>
条件渲染
当 v-if
和 v-for
同时存在于一个元素上的时候,v-if
会首先被执行。
列表渲染
<li v-for="item in items">{{ item.message }}</li>
<!-- `v-for` 你也可以使用 `of` 作为分隔符来替代 `in` -->
<li v-for="item of items">{{ item.message }}</li>
<!-- 解构 + 索引 -->
<li v-for="({ message }, index) in items">#{{index + 1}} {{ message }}</li>
<!-- 迭代对象 -->
<ul>
<li v-for="(value, key, index) in { title: 'hello', author: 'Tom' }">{{ value }}</li>
</ul>
事件处理
监听事件
用法:v-on:click="handler"
或 @click="handler"
事件处理器 (handler
) 的值可以是:
- 内联事件处理器:事件被触发时执行的内联 JavaScript 语句 (与
onclick
类似)。 - 方法事件处理器:一个指向组件上定义的方法的属性名或是路径。
内联事件处理器示例
<!-- 简单场景 -->
<button @click="count++">Add 1</button>
<!-- 类似 onclick 传递函数 -->
<button @click="increaseCount()">Add 1</button>
<!-- 访问事件参数: 使用特殊的 $event 变量 -->
<button @click="warn('Form cannot be submitted yet.', $event)">Submit</button>
<!-- 访问事件参数: 使用内联箭头函数 -->
<button @click="(event) => warn('Form cannot be submitted yet.', event)">Submit</button>
方法事件处理器
<template>
<button @click="increaseCount">Greet</button>
</template>
<script setup>
const count = ref(0);
const increaseCount = (event) => {
console.log("event target: ", event.target):
count.value ++;
}
</script>
事件修饰符
Vue 为 v-on
提供了事件修饰符。修饰符是用 .
表示的指令后缀,包含以下这些:
.stop
.prevent
.self
.capture
.once
.passive
<!-- 单击事件将停止传递 -->
<a @click.stop="doThis"></a>
<!-- 提交事件将不再重新加载页面 -->
<form @submit.prevent="onSubmit"></form>
<!-- 修饰语可以使用链式书写 -->
<a @click.stop.prevent="doThat"></a>
<!-- 也可以只有修饰符 -->
<form @submit.prevent></form>
<!-- 仅当 event.target 是元素本身时才会触发事件处理器 -->
<!-- 例如:事件处理器不来自子元素 -->
<div @click.self="doThat">...</div>
使用修饰符时需要注意调用顺序,因为相关代码是以相同的顺序生成的。因此使用 @click.prevent.self
会阻止元素及其子元素的所有点击事件的默认行为,而 @click.self.prevent
则只会阻止对元素本身的点击事件的默认行为。
按键修饰符
Vue 允许在 v-on
或 @
监听按键事件时添加按键修饰符:
<!-- 仅在 `key` 为 `Enter` 时调用 `submit` -->
<input @keyup.enter="submit" />
<input @keyup.page-down="onPageDown" />
常用的按键提供了别名:
.enter
.tab
.delete
(捕获“Delete”和“Backspace”两个按键).esc
.space
.up
.down
.left
.right
.ctrl
.alt
.shift
.meta
.exact
修饰符允许精确控制触发事件所需的系统修饰符的组合:
<!-- 当按下 Ctrl 时,即使同时按下 Alt 或 Shift 也会触发 -->
<button @click.ctrl="onClick">A</button>
<!-- 仅当按下 Ctrl 且未按任何其他键时才会触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>
<!-- 仅当没有按下任何系统按键时触发 -->
<button @click.exact="onClick">A</button>
鼠标按键修饰符
.left
.right
.middle