Composition API 入门指南
🎯 引言
学习了这篇文章后,你能理解 Vue 3 中 Composition API 的核心思想,掌握如何使用 setup()、ref、reactive 等新 API,清楚生命周期钩子的用法以及 computed 和 watch 的新写法,告别 Vue 2 中繁琐的 this 语法,用更灵活的方式构建组件逻辑。对于刚接触 Vue 3 的小伙伴来说,这将大大提升你的开发效率和代码可维护性。
✨ 为什么要有 Composition API?
Vue 2.x 用的是 Options API,也就是我们熟悉的 data、methods、computed、watch 这些选项写法。虽然简单直观,但在组件逻辑复杂时,会导致代码分散且难以维护。比如,一个组件中有多个功能模块,每个功能相关的代码却分布在 data、methods、computed 不同部分,难以一眼看出模块整体逻辑。
Composition API 诞生的目的就是为了解决这个问题。它让我们把相关逻辑放在一起,通过函数式的写法组织代码,提高复用性和代码的清晰度。
⚙️ setup() 的使用场景与逻辑
setup() 是 Composition API 的入口函数,组件创建时会调用它。这里可以进行响应式数据的声明、函数的定义以及生命周期钩子的注册。setup() 返回的对象会暴露给模板使用。
一个简单的组件示例:
<template>
<div>
<p>计数:{{ count }}</p>
<button @click="increment">加一</button>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const count = ref(0);
function increment() {
count.value++;
}
return {
count,
increment,
};
},
};
</script>
这里所有组件逻辑都写在 setup() 里,不再需要 data 或 methods。
💡 ref 与 reactive 的区别与使用
这两者都是用来声明响应式数据,但场景和本质有区别。
- ref 用来包装基本类型数据(字符串、数字、布尔),也可以包装对象,但访问时要通过 .value。
- reactive 用来将一个对象变成响应式,直接操作属性即可,不需要 .value。
示例:
import { ref, reactive } from 'vue';
const count = ref(0); // 基础类型,访问 count.value
const state = reactive({ name: '张三', age: 18 }); // 对象类型,访问 state.name
但是 reactive 不能直接包裹基本类型,比如:
const num = reactive(0); // 错误用法
🕰 生命周期钩子在 setup() 中的替代品(onMounted 等)
Vue 2 里我们用 created、mounted、updated 等生命周期选项。Composition API 把它们拆分成了独立的函数,比如 onMounted、onUpdated。
示例:
import { onMounted } from 'vue';
export default {
setup() {
onMounted(() => {
console.log('组件挂载完成');
});
},
};
这样我们能在 setup() 内部灵活调用对应钩子,逻辑更集中。
🧮 computed 与 watch 的新用法
computed 和 watch 也属于响应式 API,但写法变化不大。
computed 用于声明计算属性:
import { ref, computed } from 'vue';
const firstName = ref('张');
const lastName = ref('三');
const fullName = computed(() => {
return firstName.value + lastName.value;
});
watch 用于监听响应式数据变化,执行副作用:
import { ref, watch } from 'vue';
const count = ref(0);
watch(count, (newVal, oldVal) => {
console.log(`count 从 ${oldVal} 变成了 ${newVal}`);
});
💭 替代 this 的思维方式
在 Vue 2 中,我们通过 this 访问组件数据和方法,写法简单但容易混淆作用域。
Composition API 中,setup() 内不存在 this,上下文被移除。我们直接通过变量名访问,避免了 this 指向问题。
这就要求我们改变思维:
- 数据和方法都通过变量和函数直接操作,不用 this。
- 组件状态由一堆响应式变量构成,像普通 JS 代码一样组织。
- 模板中仍然使用变量名访问,但底层不再依赖 this。
例如:
export default {
setup() {
const count = ref(0);
function increment() {
count.value++;
}
return { count, increment };
},
};
没有了 this,我们的代码更像纯函数,易于测试和维护。
✨ script setup 语法糖
Vue3 推出了 # script setup 语法糖,简单来说,它是对传统 setup () 函数的一个极简化写法。它的优势主要体现在代码更简洁、减少模板和逻辑之间的样板代码,让开发体验更友好。
传统写法中,setup () 需要手动 return 所有模板中会用到的变量和函数,代码较为冗长,容易漏写。而 # script setup 让你无需显式 return,所有顶层声明都自动暴露给模板。
举个例子:
<template>
<button @click="increment">Count: {{ count }}</button>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0);
function increment() {
count.value++;
}
</script>
上面代码中没有 return,变量和方法直接可用,整体更清爽。能够提高开发效率。
📦 defineProps 和 defineEmits 的使用方式
script setup 提供了两个编译时的辅助函数:defineProps 和 defineEmits。
它们帮我们声明组件的 props 和 emits 类型,同时在代码中可以直接使用。
使用 defineProps
<template>
<h1>{{ props.title }} - {{ props.count }}</h1>
</template>
<script setup>
const props = defineProps({
title: String,
count: {
type: Number,
default: 0,
},
});
</script>
使用 defineEmits
<template>
<button @click="handleChange">Change</button>
</template>
<script setup>
const emit = defineEmits(['change']);
function handleChange() {
emit('change', 'value');
}
</script>
这里的 emit 就是发射事件的方法,可以传递事件名和参数。
🧾 小节总结
- Composition API 让组件逻辑更集中,解决了 Options API 代码分散的问题。
- setup() 是组件逻辑的集中地,里面用 ref、reactive 创建响应式数据。
- 生命周期钩子变成了独立函数(onMounted 等),只能在 setup() 中使用。
- computed 和 watch 的写法更灵活,支持更复杂的响应式场景。
- Composition API 去掉了 this,改成变量和函数直接操作,代码更清晰易维护。
❓ 知识问答(Q&A)
Q:为什么 Composition API 要移除 this?
A:去掉 this 可以避免作用域混乱,代码更像普通 JS,便于理解和测试。
Q:ref 和 reactive 有什么主要区别?
A:ref 用于包装基本类型,访问时用 .value;reactive 用于包装对象,直接访问属性。
Q:生命周期钩子怎么在 setup() 中使用?
A:使用对应的钩子函数,比如 onMounted(() => {...}),只能在 setup() 内调用。
🧪 小练习
练习1
用 Composition API 写一个计数器组件,实现加减功能,并且在计数变化时打印日志。
<template>
<div>
<p>计数:{{ count }}</p>
<button @click="decrement">减一</button>
<button @click="increment">加一</button>
</div>
</template>
<script setup>
import { ref, watch } from 'vue';
const count = ref(0);
// 请实现 decrement 和 increment 函数
// 监听 count 变化,打印日志
</script>
练习2
写一个组件,使用 reactive 定义一个用户对象,包含 name、age 两个属性,并用 computed 计算用户的信息描述。
<template>
<div>
<p>用户信息:{{ userInfo }}</p>
</div>
</template>
<script setup>
import { reactive, computed } from 'vue';
const user = reactive({
name: '李四',
age: 20,
});
// 请定义 computed 属性 userInfo,格式如:李四,20岁
</script>
🎉 恭喜你已经掌握 Composition API 的核心技能啦!能够用 Vue 3 写出可维护性更高、逻辑更清晰的组件了!继续多练习,相信你会成为 Vue 3 高手!
