文章目录
- 前言
- [一、 组件基础与结构演进](#一、 组件基础与结构演进)
-
- [1.1 Vue 2 传统的组件定义方式](#1.1 Vue 2 传统的组件定义方式)
- [1.2 Vue 3 模板新特性:打破单根节点限制 (Fragments)](#1.2 Vue 3 模板新特性:打破单根节点限制 (Fragments))
- [二、 架构范式:Options API vs. Composition API](#二、 架构范式:Options API vs. Composition API)
-
- [2.1 Options API (配置式 API)](#2.1 Options API (配置式 API))
- [2.2 Composition API (组合式 API)](#2.2 Composition API (组合式 API))
- [三、 核心语法糖:`<script setup>`](#三、 核心语法糖:
<script setup>) - [四、 响应式数据全景(Ref & Reactive)](#四、 响应式数据全景(Ref & Reactive))
-
- [4.1 ref 创建基本类型的响应式数据](#4.1 ref 创建基本类型的响应式数据)
- [4.2 reactive 创建对象类型的响应式数据](#4.2 reactive 创建对象类型的响应式数据)
- [4.3 ref 创建对象类型的响应式数据](#4.3 ref 创建对象类型的响应式数据)
- [4.4 ref 与 reactive 的深度对比](#4.4 ref 与 reactive 的深度对比)
- [五、 响应式转换工具:toRef 与 toRefs](#五、 响应式转换工具:toRef 与 toRefs)
-
- [5.1 为什么需要它们?](#5.1 为什么需要它们?)
- [5.2 toRef](#5.2 toRef)
- [5.3 toRefs](#5.3 toRefs)
- [六、 高级响应式特性:computed 与 watch](#六、 高级响应式特性:computed 与 watch)
-
- [6.1 computed 计算属性](#6.1 computed 计算属性)
- [6.2 watch 侦听器](#6.2 watch 侦听器)
- 结语
前言
Vue 3 带来的不仅是性能提升,更是组件编写范式的全面革新。本文从 Options API 到 Composition API 的演进切入,深入解析 <script setup> 语法糖、响应式系统与计算属性的核心机制,助你快速掌握现代 Vue 开发的最佳实践。
一、 组件基础与结构演进
1.1 Vue 2 传统的组件定义方式
在 Vue 2 中(结合 TypeScript 时),组件通常采用类或者对象配置的形式进行导出。
javascript
<script lang="ts">
export default {
name: 'App' // 明确指定组件名,利于在开发者工具中调试和组件递归调用
}
</script>
- 特点 :属于典型的 Options API(配置式API),组件的名字、数据、方法等都要写在固定的配置项中。
1.2 Vue 3 模板新特性:打破单根节点限制 (Fragments)
- Vue 2 痛点 :
<template>内部必须有且仅有一个根标签(通常包裹一个<div>),否则编译报错。 - Vue 3 优化 :引入了 Fragments(片段) 特性。组件的模板中可以没有根标签,多个同级标签可以直接并列编写。
- 好处:减少了无意义的 DOM 层级嵌套,优化了内存占用和渲染性能。
二、 架构范式:Options API vs. Composition API
2.1 Options API (配置式 API)
- 代表版本:Vue 2
- 编写方式 :数据写在
data、方法写在methods、计算属性写在computed、监听器写在watch。 - 痛点 :当组件业务变得极其复杂时,同一功能模块的逻辑会被拆散到不同的配置项中。开发者在维护代码时,需要频繁地上下滚动页面,极其不利于代码的阅读和复用。
2.2 Composition API (组合式 API)
- 代表版本:Vue 3
- 编写方式 :以功能为单位,将相同功能的响应式数据、方法、计算属性有机地组合在一起,甚至可以抽离成独立的
hooks文件。 - 优势 :
- 完美的高聚合、低耦合,代码按业务逻辑聚集。
- 极大地方便了代码的复用(取代了 Vue 2 中饱受诟病的
mixins)。 - 对 TypeScript 的类型推导支持更加友好。
三、 核心语法糖:<script setup>
setup 是 Vue 3 组合式 API 的入口。普通的 setup() 函数需要手动返回(return)每一个变量和方法,模板才能使用,闭包写法较为繁琐。
Vue 3 推出了 <script setup> 语法糖:
javascript
<script setup lang="ts">
// 在这里声明的变量、函数、import引入的组件,不需要手动 return,在 template 中可以直接使用!
const msg = 'Hello Vue 3!'
</script>
<template>
<h1>{{ msg }}</h1>
</template>
- 核心优势 :
- 代码极其精简,告别了冗余的
export default和return。 - 引入的子组件自动注册 ,直接在模板中写标签即可使用,无需显式声明
components。
- 代码极其精简,告别了冗余的
四、 响应式数据全景(Ref & Reactive)
4.1 ref 创建基本类型的响应式数据
- 语法 :
const count = ref(0) - 底层原理 :基于
Object.defineProperty()的get和set进行数据劫持,封装为RefImpl(引用实现)对象。 - 读写规则 :在
<script>中读写必须加上.value;但在<template>模板中解析时,Vue 会自动解包,不需要 加.value。
4.2 reactive 创建对象类型的响应式数据
- 语法 :
const state = reactive({ name: '张三', age: 18 }) - 底层原理 :基于 ES6 的 Proxy(代理) 实现,直接拦截整个对象的操作。
- 读写规则 :无论在
<script>还是<template>中,都直接通过state.name访问,绝不使用.value。
4.3 ref 创建对象类型的响应式数据
- 语法 :
const userInfo = ref({ name: '李四' }) - 底层原理 :当把一个对象传给
ref时,它内部会自动调用reactive来将其转化为 Proxy 代理对象。 - 读写规则 :在
<script>中访问时,需要写成userInfo.value.name。
4.4 ref 与 reactive 的深度对比
| 维度 | ref | reactive |
|---|---|---|
| 定义数据类型 | 基类类型(String、Number等)、对象类型 | 只能定义对象类型(Object、Array等) |
| 访问方式 | 脚本中必须带 .value,模板中不用 |
任何地方都不带 .value |
| 重新赋值(重写) | 可以直接修改 .value 指向一个新对象(依然保持响应式) |
不能直接赋新对象(会丢失响应式 ),需使用 Object.assign 或修改内部属性 |
| 解构支持 | 不适用 | 直接解构会丢失响应式 |
五、 响应式转换工具:toRef 与 toRefs
5.1 为什么需要它们?
当我们在组件中有一个 reactive 对象,如果直接在模板中写一长串前缀(如 {``{ user.nested.info.name }})很麻烦。但如果我们尝试用 ES6 结构赋值:
javascript
const user = reactive({ name: 'Tom', age: 20 })
const { name, age } = user // 此时 name 和 age 变成了普通字符串和数字,丢失了响应式!
为了让对象解构出来的单体属性依然保持响应式 ,就需要使用 toRef 和 toRefs。
5.2 toRef
- 作用 :为响应式对象上的某个特定属性,创建一个对应的
ref。这个ref与源属性保持同步链接。 - 语法 :
const nameRef = toRef(user, 'name')
5.3 toRefs
- 作用 :批量处理。将一个
reactive对象转换为一个普通对象,但这个普通对象的每一个属性都是一个对应的ref。 - 语法:
javascript
const user = reactive({ name: 'Tom', age: 20 })
// 批量转换并解构
const { name, age } = toRefs(user)
// 此时 name 和 age 都是独立的 RefImpl 对象,且与 user 内部属性联动,可直接在模板中使用!
六、 高级响应式特性:computed 与 watch
6.1 computed 计算属性
- 作用:根据已有的响应式数据,衍生出新的计算数据。
- 特点 :具备缓存机制。只有当它依赖的响应式源数据发生改变时,它才会重新计算;否则多次访问会直接读取缓存,性能极高。
- Vue 3 写法:
javascript
import { ref, computed } from 'vue'
const firstName = ref('张')
const lastName = ref('三')
// 简写形式(只读)
const fullName = computed(() => {
return firstName.value + lastName.value
})
6.2 watch 侦听器
- 作用:监视一个或多个特定响应式数据的变化,当数据变化时执行特定的回调函数(侧重于执行业务旁路逻辑,如异步请求、本地存储等)。
- Vue 3 写法特性 :
- 可以直接监听
ref、reactive对象、一个 Getter 函数,或者由它们组成的数组。 - 提供了丰富的配置项,例如
deep: true(深度监听)、immediate: true(立即初始执行一次)。
- 可以直接监听
javascript
import { ref, watch } from 'vue'
const count = ref(0)
// 监听单个 ref
watch(count, (newValue, oldValue) => {
console.log(`count从 ${oldValue} 变为了 ${newValue}`)
})
结语
掌握 ref 与 reactive 的差异边界、toRefs 的解构技巧以及 computed 的缓存机制,是驾驭 Vue 3 响应式系统的关键。组合式 API 让代码按业务逻辑聚合,为复杂应用的维护与复用打开了全新空间。