Vue3的选项式API和组合式API对比
Vue3的选项式API和组合式API对比
Vue 3 中的选项式 API(Options API)和组合式 API(Composition API)是两种构建组件的方式。它们本质上是两种不同的组织逻辑和编写代码的风格,都可以实现相同的功能,但各有优缺点和适用场景。
一、选项式 API(Options API)
核心思想:
用选项对象来组织组件的代码,比如 data
、methods
、computed
、watch
等。每个功能点都有自己的专属配置项。
写法示例:
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Add</button>
</div>
</template>
<script>
export default {
data() {
return {
count: 0
};
},
methods: {
increment() {
this.count++;
}
}
}
</script>
二、组合式API(Composition API)
核心思想:
通过引入 Vue 3 的 setup()
函数,在其中使用 ref
、reactive
、computed
、watch
、onMounted
等函数组合逻辑,更加灵活。
setup() 是 Vue 组件在创建时最先执行的函数,所有组合式逻辑(如 ref、reactive、computed、watch、onMounted 等)都在里面使用,并最终将它们“暴露”给模板*
写法示例
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Add</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0);
const increment = () => {
count.value++;
}
</script>
三、两种API的细致对比
下面展示一个 用户信息表单组件,可以:
-
输入用户姓名和年龄
-
实时显示用户是否成年(18岁以上)
-
在用户信息变化时写入 localStorage
-
页面加载时从 localStorage 读取用户信息
-
有表单验证(如年龄必须为数字,且 ≥ 0
选项式 API 实现
<!-- UserFormOptions.vue -->
<template>
<div>
<h2>选项式 API 表单</h2>
<input v-model="user.name" placeholder="姓名" />
<input v-model.number="user.age" type="number" placeholder="年龄" />
<p>是否成年:{{ isAdult ? '是' : '否' }}</p>
<p v-if="error">{{ error }}</p>
</div>
</template>
<script>
export default {
data() {
return {
user: {
name: '',
age: 0
},
error: ''
};
},
computed: {
isAdult() {
return this.user.age >= 18;
}
},
watch: {
user: {
handler(newVal) {
localStorage.setItem('user', JSON.stringify(newVal));
},
deep: true
}
},
mounted() {
const saved = localStorage.getItem('user');
if (saved) {
this.user = JSON.parse(saved);
}
},
methods: {
validate() {
if (typeof this.user.age !== 'number' || this.user.age < 0) {
this.error = '年龄必须是非负数字';
} else {
this.error = '';
}
}
},
updated() {
this.validate();
}
};
</script>
组合式 API 实现
<!-- UserFormComposition.vue -->
<template>
<div>
<h2>组合式 API 表单</h2>
<input v-model="user.name" placeholder="姓名" />
<input v-model.number="user.age" type="number" placeholder="年龄" />
<p>是否成年:{{ isAdult ? '是' : '否' }}</p>
<p v-if="error">{{ error }}</p>
</div>
</template>
<script setup>
import { reactive, computed, watch, onMounted, ref } from 'vue';
const user = reactive({
name: '',
age: 0
});
const error = ref('');
const isAdult = computed(() => user.age >= 18);
const validate = () => {
if (typeof user.age !== 'number' || user.age < 0) {
error.value = '年龄必须是非负数字';
} else {
error.value = '';
}
};
watch(user, (newVal) => {
localStorage.setItem('user', JSON.stringify(newVal));
validate();
}, { deep: true });
onMounted(() => {
const saved = localStorage.getItem('user');
if (saved) {
const parsed = JSON.parse(saved);
user.name = parsed.name;
user.age = parsed.age;
}
});
</script>
对比总结
点 | 选项式 API | 组合式 API |
---|---|---|
响应式状态定义 | data() 返回对象 | ref() / reactive() 明确声明 |
生命周期钩子 | mounted() | onMounted() |
计算属性 | computed: { isAdult() {} } | const isAdult = computed(...) |
监听器 | watch: { user: { handler, deep } } | watch(user, callback, { deep: true }) |
表单验证逻辑位置 | 分布在 methods 和 updated 中 | 集中在 watch 内部或 validate() 函数 |
代码结构 | 分块清晰,逻辑分散 | 结构集中,逻辑归一 |
可复用性 | 较差,逻辑难抽离 | 好,可提取为 composable |
四、可复用的组合式函数
现在我将把上面的用户信息表单逻辑提取为一个 组合式函数(composable),这样多个组件都可以轻松复用它,而不用重复写逻辑。
自定义组合函数(useUserForm.js)
// composables/useUserForm.js
import { reactive, computed, watch, onMounted, ref } from 'vue';
export function useUserForm(storageKey = 'user') {
const user = reactive({
name: '',
age: 0
});
const error = ref('');
const isAdult = computed(() => user.age >= 18);
const validate = () => {
if (typeof user.age !== 'number' || user.age < 0) {
error.value = '年龄必须是非负数字';
} else {
error.value = '';
}
};
watch(user, (newVal) => {
localStorage.setItem(storageKey, JSON.stringify(newVal));
validate();
}, { deep: true });
onMounted(() => {
const saved = localStorage.getItem(storageKey);
if (saved) {
const parsed = JSON.parse(saved);
user.name = parsed.name;
user.age = parsed.age;
}
});
return {
user,
error,
isAdult,
validate
};
}
在组件中使用(UserForm.vue)
<template>
<div>
<h2>用户表单</h2>
<input v-model="user.name" placeholder="姓名" />
<input v-model.number="user.age" type="number" placeholder="年龄" />
<p>是否成年:{{ isAdult ? '是' : '否' }}</p>
<p v-if="error">{{ error }}</p>
</div>
</template>
<script setup>
import { useUserForm } from '@/composables/useUserForm';
const { user, isAdult, error } = useUserForm();
</script>
注意:选项式 API 设计上不支持直接通过函数进行逻辑复用;组合式 API 是为此场景而生的。
五、总结建议
项目阶段/特点 | 推荐使用 |
---|---|
学习入门 | Options API |
小型项目 | Options API |
中大型项目 | Composition API |
追求逻辑复用/TS 类型 | Composition API |
要做 Vue3 最佳实践项目 | Composition API |