vue3 系列:Vue3 官方文档速通

前言:参考Vue 官方文档,本文档主要学习组合式 API。

一 开始

1. 简介

1.1 什么是 Vue?

一款 JS 框架,并有两个核心功能:声明式渲染、响应性。

 1.2 渐进式框架

根据不同的需求场景,使用不同方式的 Vue,比如:

        无需构建步骤,直接引入 vuejs。

        在任何页面中作为 Web Components 嵌入

        使用构建步骤,单页应用 (SPA)

        全栈 / 服务端渲染 (SSR)

        Jamstack / 静态站点生成 (SSG)

        开发桌面端、移动端、WebGL,甚至是命令行终端中的界面

Vue 为什么可以称为“渐进式框架”:它是一个可以与你共同成长、适应你不同需求的框架。

 1.3 单文件组件

单文件组件是 Vue 的标志性功能。*.vue、SFC 就是单文件组件:将一个组件的逻辑 (JS),模板 (HTML) 和样式 (CSS) 封装在同一个文件里。

 1.4 API 风格

选项式 API(Options API):包含多个选项的对象来描述组件的逻辑,例如 data、methods 和 mounted。

组合式 API(Composition API):使用导入的 API 函数来描述组件逻辑。通常会与

{{ message }}

 通过 CDN 以及原生 ES 模块使用 Vue:

{{ message }}

使用导入映射表 (Import Maps) 来告诉浏览器如何定位到导入的 vue:



{{ message }}

分割代码成单独的 JS 文件,以便管理。


// my-component.js
import { ref } from "vue";
export default {
  setup() {
    const count = ref(0);
    return { count };
  },
  template: `
count is {{ count }}
`, };

注意:直接点击 index.html,会抛错误,因为 ES 模块不能通过 file:// 协议工作。只能通过 http:// 协议工作。需要启动一个本地的 HTTP 服务器,通过命令行在 HTML 文件所在文件夹下运行 npx serve。

 二 基础

1. 创建一个 Vue 应用

1.1 应用实例

通过 createApp 函数创建 Vue 应用实例:

import { createApp } from "vue";

const app = createApp({
  /* 根组件选项 */
});

1.2 根组件

createApp 需要传入一个根组件,其他组件将作为其子组件:

import { createApp } from "vue";
// 从一个单文件组件中导入根组件
import App from "./App.vue";

const app = createApp(App);

1.3 挂载应用

调用 .mount() 方法,传入一个 DOM 元素或是 CSS 选择器。它的返回值是根组件实例而非应用实例:

import { createApp } from "vue";
// 从一个单文件组件中导入根组件
import App from "./App.vue";

const app = createApp(App);
app.mount("#app");

1.4 应用配置

注意:确保在挂载应用实例之前完成所有应用配置!

import { createApp } from "vue";
// 从一个单文件组件中导入根组件
import App from "./App.vue";

const app = createApp(App);

// 应用实例的 .config 对象可以进行一些配置,例如配置错误处理器:用来捕获所有子组件上的错误:
app.config.errorHandler = (err) => {
  /* 处理错误 */
};

// 全局挂载组件
app.component("TodoDeleteButton", TodoDeleteButton);

// 全局属性的对象。
app.config.globalProperties.msg = "hello";

app.mount("#app");

1.5 多个应用实例

每个应用都拥有自己的用于配置和全局资源的作用域:

const app1 = createApp({
  /* ... */
});
app1.mount("#container-1");

const app2 = createApp({
  /* ... */
});
app2.mount("#container-2");

2. 模板语法

2.1 文本插值

最基本的数据绑定是文本插值,使用“Mustache”语法 (即双大括号):

Message: {{ msg }}

2.2 原始 HTML

双大括号会将数据解释为纯文本,若想插入 HTML,需要使用 v-html 指令。

安全警告:动态渲染 HTML 是很危险的,容易造成 XSS 漏洞。仅在内容安全可信时再使用 v-html,并且永远不要使用用户提供的 HTML 内容。

Using text interpolation: {{ rawHtml }}

Using v-html directive:

2.3 Attribute 绑定

绑定 attribute,使用 v-bind 指令:

绑定多个值,通过不带参数的 v-bind。

const objectOfAttrs = {
  id: "container",
  class: "wrapper",
};

2.4 使用 JS 表达式

数据绑定都支持完整的 JS 表达式,也就是一段能够被求值的 JS 代码。一个简单的判断方法是是否可以合法地写在 return 后面:

{{ number + 1 }}

{{ ok ? 'YES' : 'NO' }}

{{ message.split('').reverse().join('') }}

可以在绑定的表达式中使用一个组件暴露的方法:

2.5 指令 Directives

指 v- 前缀的特殊 attribute。它的值为 JS 表达式(v-for、v-on、v-slot 除外),指令值变化时响应式的更新 DOM,比如 v-if:

Now you see me

带参数的指令,用':'隔开:

 ... 

 ... 

指令的参数,也可以动态绑定,用 '[ ]' 包裹:

 ... 

 ... 

带修饰符的指令,用 '.' 隔开:


...

3. 响应式基础

3.1 声明响应式状态

官方推荐使用 ref() 函数来声明响应式状态:

import { ref } from "vue";

const count = ref(0);

ref() 接收参数,并返回一个带有 .value 属性的 ref 对象:

const count = ref(0);

console.log(count); // { value: 0 }
console.log(count.value); // 0

count.value++;
console.log(count.value); // 1

在模板中使用 ref 变量,不需要添加 .value。ref 会自动解包。也可以直接在事件监听器中改变一个 ref:

通过单文件组件(SFC),使用

为什么使用 ref,而不是普通的变量。这是因为 Vue 需要通过.value 属性来实现状态响应性。基础原理是在 getter 中追踪,在 setter 中触发:

// 伪代码,不是真正的实现
const myRef = {
  _value: 0,
  get value() {
    track();
    return this._value;
  },
  set value(newValue) {
    this._value = newValue;
    trigger();
  },
};

要等待 DOM 更新完成后再执行额外的代码,可以使用 nextTick() 全局 API:

import { nextTick } from "vue";

async function increment() {
  count.value++;
  await nextTick();
  // 现在 DOM 已经更新了
}

3.2 reactive()

reactive(),参数只能是对象类型,返回的是一个原始对象的 Proxy,它和原始对象是不相等的:

const raw = {};
const proxy = reactive(raw);

// 代理对象和原始对象不是全等的
console.log(proxy === raw); // false

reactive() 局限性包括:只能用于对象类型(对象,数组,Map,Set)、不能替换整个对象、对结构操作不友好:

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);

reactive() API 有一些局限性,官方建议使用 ref() 作为声明响应式状态的主要 API。博主个人还是喜欢 ref,reactive 混着用,注意那些局限性就可以了。

 3.3 额外的 ref 解包细节

一个 ref 会在作为响应式对象的属性被访问或修改时自动解包:

const count = ref(0);
const state = reactive({
  count,
});

console.log(state.count); // 0

state.count = 1;
console.log(count.value); // 1

 4. 计算属性

4.1 基础示例

computed() 方法期望接收一个 getter 函数,返回为一个计算属性 ref:



4.2 计算属性缓存 vs 方法

计算属性值会基于其响应式依赖被缓存。方法调用则总会在重新渲染时再次执行。

 4.3 可写计算属性

计算属性默认是只读的。但可以通过设置 get 和 set 函数变成可读可写:

4.4 最佳实践

使用计算属性,不要在里面做异步请求和修改 DOM。并且尽量保持只读。

5. 类与样式绑定

5.1 绑定 HTML class

通过对象来动态切换 class:

可以直接绑定一个对象:

const classObject = reactive({
  active: true,
  "text-danger": false,
});

通过数组渲染多个 class:

const activeClass = ref("active");
const errorClass = ref("text-danger");

数组中也可以使用 JS 表达式:

如果组件有多个根元素,透传的 class 需要通过组件的 $attrs 属性来实现指定:


Hi!

This is a child component

Hi!

This is a child component

5.2 绑定内联样式

值为对象,对应的是 style 属性:

const activeColor = ref("red");
const fontSize = ref(30);

直接绑定一个样式对象使模板更加简洁:

const styleObject = reactive({
  color: "red",
  fontSize: "13px",
});

还可以绑定一个包含多个样式对象的数组:

6. 条件渲染

6.1 v-if、v-else、v-else-if

v-if 指令用于条件性地渲染内容。当值为真时才被渲染:

Vue is awesome!

v-else 为 v-if 添加一个“else 区块”。并且必须跟在一个 v-if 或者 v-else-if 元素后面:



Vue is awesome!

Oh no

v-else-if 提供的是相应于 v-if 的“else if 区块”。可以连续多次使用。并且必须跟在一个 v-if 或者 v-else-if 元素后面:

A
B
C
Not A/B/C

可以使用