Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

Vue3基础

介绍

Vue 是一款用于构建用户界面的前端框架。其基于标准 HTML、CSS 与 JavaScript 构建,提供了一套声明式的、组件化的编程模型,有效地提升了开发用户界面的效率。
其特色有:

  • 声明式渲染:基于标准 HTML 拓展了一套模板语法,可以声明式地描述最终输出的 HTML 和 JavaScript 状态之间的关系。
  • 响应性:会自动跟踪 JavaScript 状态并在其发生变化时响应式地更新 DOM。

模板语法

插值语法

在Vue中允许在HTML标签内使用胡子语法Mustache,即使用{{ }}将 js右值表达式 包裹。
js右值表达式 将会以纯文本形式插入,不会解析其中的HTML标签。

1
<span> Message: {{ msg }} </span> <span> {{ isCheck ? "选中" : "未选中"}} </span>

指令语法

Vue 中的指令都是以 v- 开头,在HTML标签头中使用。
用于在表达式的值变化时响应式地更新 DOM。
<标签 v-指令名:参数="js右值表达式"></标签>
其中有的指令可以省略 参数、表达式。
其内置指令有:

  • v-model:表单输入绑定会根据所使用的元素自动使用对应的 DOM 属性和事件组合
    <input v-model="text">
  • v-text:更新元素的文本内容。相当于通过设置元素的 textContent 属性
    <span v-text="msg"></span>
  • v-html:更新元素的 innerHTML。
    <div v-html="html"></div>
  • v-show:判断元素是否可见。
    <h1 v-show="ok">Hello!</h1>
  • v-if:判断元素是否渲染。
    <h1 v-if="ok">Hello!</h1>
  • v-else:v-if 或 v-if / v-else-if 链式调用的 else 块
  • v-else-if​:v-if 链式调用的 else if 块
  • v-for:根据数据多次渲染元素或模板块。
    1
    <div v-for="item in items" :key="item.id">{{ item.text }}</div>
  • v-bind:动态绑定元素v-bind:绑定的元素可以缩写成:绑定的元素
    <div :class="{ active: isActive }"></div>
  • v-on:绑定事件监听器。
    可以使用 @ 来代替 v-on:
    其参数后可以添加一些修饰符,如下:
    • .stop:停止传播,相当于调用 event.stopPropagation()。
    • .prevent:取消默认行为,相当于调用 event.preventDefault()。
    • .capture:在捕获模式添加事件监听器。
    • .self:只有事件从元素本身发出才触发处理函数。
    • .{keyAlias}:只在某些按键下触发处理函数。
    • .once:最多触发一次处理函数。
    • .left:只在鼠标左键事件触发处理函数。
    • .right:只在鼠标右键事件触发处理函数。
    • .middle:只在鼠标中键事件触发处理函数。
    • .passive:通过 { passive: true } 附加一个 DOM 事件。

响应式

ref

使用 ref() 函数可以声明一个响应式的状态。ref() 接收一个任意类型的值作为初始值,并返回一个响应式对象 Ref<T>。该对象只有一个 .value 属性,指向传入的值。

在 TypeScript 中,ref() 会根据初始值自动推断类型,也可以通过泛型显式指定。

在模板中使用 ref 声明的响应式数据时,Vue 会自动解包,无需 .value。但在 <script> 的 TypeScript 代码中读取或修改其值时,必须通过 .value

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<script setup lang="ts">
import { ref } from "vue";

interface User {
name: string;
age: number;
}

const user = ref<User>({
name: "张三",
age: 18,
});

function growUp() {
user.value.age++;
}
</script>

<template>
<p>{{ user.name }} 今年 {{ user.age }} 岁</p>
<button @click="growUp">长大一岁</button>
</template>

ref 几乎可以包裹任意类型的值:原始类型(如 numberstringboolean)、对象、数组等。当 ref 的值为对象或数组时,Vue 会调用 reactive() 将其内部属性也转为响应式。

ref 底层实现了一个带有 .value 的响应式对象。Vue 在模板编译阶段会识别 ref 变量,在渲染访问时自动解包;在代码中访问时则通过依赖收集与触发,来实现 DOM 的自动更新。

reactive

reactive() 用于将对象转换为响应式对象,适合处理结构复杂的状态(如表单、配置对象)。与 ref 不同,reactive 返回的代理对象可以直接访问属性,无需 .value
ref 相同,reactive() 会根据传入对象自动推断类型,也可以显式传入接口。

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
<script setup lang="ts">
import { reactive } from "vue";

interface State {
count: number;
message: string;
}

const state = reactive<State>({
count: 0,
message: "Hello Vue",
});

function increment() {
state.count++;
}

function updateMessage(event: Event) {
state.message = (event.target as HTMLInputElement).value;
}
</script>

<template>
<p>计数:{{ state.count }}</p>
<button @click="increment">+1</button>
<input :value="state.message" @input="updateMessage" />
<p>输入的内容:{{ state.message }}</p>
</template>

reactive 基于 Proxy 实现响应式代理。访问属性时收集依赖,修改属性时触发依赖更新。对于深层对象,Vue 会递归地将其属性也转为响应式。
由于 Proxy Api的限制reactive 只能用于对象类型,不能用于原始类型。

计算属性

计算属性使用 computed() 声明,它会根据依赖的响应式数据计算出一个新值,并且具有缓存特性:只有当依赖的响应式数据发生变化时,才会重新计算;否则多次访问会返回上一次缓存的结果。
computed() 会根据回调的返回值自动推断计算属性的类型,也可以显式通过泛型指定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script setup lang="ts">
import { ref, computed } from "vue";

const firstName = ref("张");
const lastName = ref("三");

const fullName = computed<string>(() => {
return firstName.value + lastName.value;
});

function changeName() {
firstName.value = "李";
lastName.value = "四";
}
</script>

<template>
<p>姓名:{{ fullName }}</p>
<button @click="changeName">改名</button>
</template>

计算属性也可以声明为可写的,通过提供 getset

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
<script setup lang="ts">
import { ref, computed } from "vue";

const firstName = ref("张");
const lastName = ref("三");

const fullName = computed<string>({
get() {
return firstName.value + "-" + lastName.value;
},
set(newValue: string) {
const [first, last] = newValue.split("-");
firstName.value = first;
lastName.value = last;
},
});

function updateName() {
fullName.value = "王-五";
}
</script>

<template>
<p>姓名:{{ fullName }}</p>
<button @click="updateName">改为王-五</button>
</template>

在模板中调用方法 {{ getFullName() }} 每次渲染都会重新执行;而计算属性 {{ fullName }} 只在其依赖变化时重新执行,性能更优。
computed 内部维护了一个 dirty(脏)标志。首次访问或依赖变化时标记为脏,再次访问时重新计算并缓存;依赖未变化时直接返回缓存值。Vue 通过响应式依赖追踪自动建立计算属性与 ref/reactive 之间的依赖关系。

侦听器

watch

侦听器使用 watch() 声明,用于在响应式数据变化时执行副作用逻辑。它可以监听单个 ref、一个返回响应式数据的 getter 函数,或一个包含多个数据源的数组。

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
<script setup lang="ts">
import { ref, watch } from "vue";

const question = ref<string>("");
const answer = ref<string>("请输入问题");

watch(question, async (newValue: string, oldValue: string) => {
if (newValue.indexOf("?") === -1) {
answer.value = "问题通常需要包含一个问号。";
return;
}
answer.value = "思考中...";
// 模拟异步请求
await new Promise((resolve) => setTimeout(resolve, 500));
answer.value = "答案是 42";
});
</script>

<template>
<p>
提问:
<input v-model="question" />
</p>
<p>{{ answer }}</p>
</template>

监听多个数据源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script setup lang="ts">
import { ref, watch } from "vue";

const x = ref(0);
const y = ref(0);

watch([x, y], ([newX, newY]: [number, number]) => {
console.log(`x 变为 ${newX},y 变为 ${newY}`);
});

function update() {
x.value++;
y.value += 2;
}
</script>

<template>
<button @click="update">更新 x 和 y</button>
</template>

常用选项:

  • immediate: true:创建侦听器时立即执行一次回调。
  • deep: true:对对象内部属性的变化进行深度监听。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
interface NestedState {
nested: {
count: number;
};
}

const obj = ref<NestedState>({ nested: { count: 0 } });

watch(
obj,
(newValue: NestedState, oldValue: NestedState) => {
console.log("对象变化了", newValue.nested.count);
},
{ deep: true },
);

watch 会在初始化时收集被监听数据(或 getter 返回数据)的依赖。当这些响应式数据发生变化时,Vue 的响应式系统会通知 watch 的回调函数执行。

watchEffect

**watchEffect()**:立即运行一个函数,并自动追踪其中使用的响应式依赖,依赖变化时重新执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
<script setup lang="ts">
import { ref, watchEffect } from "vue";

const count = ref(0);

watchEffect(() => {
console.log("count 的值为:", count.value);
});

function add() {
count.value++;
}
</script>

watch 不同,watchEffect 在执行过程中自动追踪访问到的响应式数据。


参考资料

vue.js 快速上手文档
Vue.js API 参考

关于本人

HaiYao的博客
Git主页

评论