跳到主要内容

Composition API vs Options API

问题

Vue 3 的 Composition API 和 Options API 有什么区别?各有什么优缺点?

答案

Vue 提供两种组件编写方式:Options API(选项式)和 Composition API(组合式)。

基本对比

<template>
<div>
<p>{{ count }}</p>
<p>{{ doubleCount }}</p>
<button @click="increment">+1</button>
</div>
</template>

<script>
export default {
data() {
return {
count: 0
};
},
computed: {
doubleCount() {
return this.count * 2;
}
},
methods: {
increment() {
this.count++;
}
},
mounted() {
console.log('mounted');
}
};
</script>

核心区别

维度Options APIComposition API
组织方式按选项类型(data/methods/computed)按逻辑功能
this需要 this 访问不需要 this
逻辑复用MixinsComposables
TypeScript支持一般完美支持
代码压缩一般更好
学习曲线中等

Options API 的问题

当组件变得复杂时,Options API 会导致相关逻辑分散

// Options API:相关逻辑分散在不同选项中
export default {
data() {
return {
// 功能 A 的数据
searchQuery: '',
searchResults: [],

// 功能 B 的数据
filters: {},

// 功能 C 的数据
pagination: { page: 1, size: 10 }
};
},
computed: {
// 功能 A 的计算属性
filteredResults() { /* ... */ },

// 功能 B 的计算属性
activeFilters() { /* ... */ }
},
methods: {
// 功能 A 的方法
search() { /* ... */ },

// 功能 B 的方法
applyFilter() { /* ... */ },

// 功能 C 的方法
changePage() { /* ... */ }
},
watch: {
// 功能 A 的侦听器
searchQuery() { /* ... */ },

// 功能 C 的侦听器
'pagination.page'() { /* ... */ }
}
};

Composition API 的优势

按逻辑功能组织代码

// Composition API:相关逻辑放在一起
import { ref, computed, watch } from 'vue';

// 功能 A:搜索
function useSearch() {
const searchQuery = ref('');
const searchResults = ref([]);

const filteredResults = computed(() => {
// 过滤逻辑
});

function search() {
// 搜索逻辑
}

watch(searchQuery, () => {
// 监听逻辑
});

return { searchQuery, searchResults, filteredResults, search };
}

// 功能 B:过滤
function useFilters() {
const filters = ref({});
const activeFilters = computed(() => { /* ... */ });
function applyFilter() { /* ... */ }
return { filters, activeFilters, applyFilter };
}

// 功能 C:分页
function usePagination() {
const pagination = ref({ page: 1, size: 10 });
function changePage(page: number) { /* ... */ }
return { pagination, changePage };
}

// 组件中使用
export default {
setup() {
const { searchQuery, filteredResults, search } = useSearch();
const { filters, applyFilter } = useFilters();
const { pagination, changePage } = usePagination();

return { searchQuery, filteredResults, search, filters, applyFilter, pagination, changePage };
}
};

逻辑复用对比

// mixin 定义
const mouseMixin = {
data() {
return {
x: 0,
y: 0
};
},
methods: {
update(e: MouseEvent) {
this.x = e.pageX;
this.y = e.pageY;
}
},
mounted() {
window.addEventListener('mousemove', this.update);
},
unmounted() {
window.removeEventListener('mousemove', this.update);
}
};

// 组件中使用
export default {
mixins: [mouseMixin],
// 问题1:属性来源不清晰
// 问题2:命名冲突
// 问题3:无法传参
};

Mixins vs Composables

问题MixinsComposables
属性来源不清晰,难以追踪显式导入,清晰可见
命名冲突容易冲突,隐式覆盖可以解构重命名
传递参数不灵活支持参数
TypeScript类型推断困难完美支持
逻辑组合难以组合多个 mixin自由组合

TypeScript 支持对比

import { defineComponent, PropType } from 'vue';

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

export default defineComponent({
props: {
user: {
type: Object as PropType<User>,
required: true
}
},
data() {
return {
count: 0 // 类型推断为 number
};
},
computed: {
// 需要显式标注返回类型才能正确推断
doubleCount(): number {
return this.count * 2;
}
},
methods: {
// this 类型推断可能不完整
increment() {
this.count++;
}
}
});

何时使用哪种 API

场景推荐
小型项目、简单组件Options API(更直观)
大型项目、复杂组件Composition API(更灵活)
需要逻辑复用Composition API
使用 TypeScriptComposition API
Vue 2 迁移项目可以混用,逐步迁移

常见面试问题

Q1: Composition API 相比 Options API 有什么优势?

答案

  1. 更好的代码组织:将相关逻辑放在一起,而非分散在不同选项中
  2. 更好的逻辑复用:Composables 替代 Mixins,解决了命名冲突、来源不清等问题
  3. 更好的 TypeScript 支持:不依赖 this,类型推断更准确
  4. 更小的打包体积:变量名可以被压缩(不像 Options API 的属性名)
  5. 更灵活的组合:可以自由组合多个 Composables

Q2: Options API 还有存在的必要吗?

答案

。两种 API 会长期共存:

  1. 学习曲线更低:对初学者更友好
  2. 简单场景够用:小型组件用 Options API 更直观
  3. 迁移成本:大量 Vue 2 项目仍在使用
  4. 混用支持:Vue 3 允许在同一组件中混用
// Vue 3 中混用两种 API
export default {
data() {
return { count: 0 };
},
setup() {
const name = ref('Vue');
return { name };
}
};

Q3: setup 中为什么不能使用 this?

答案

setup 在组件实例创建之前执行,此时 this 还不存在:

export default {
setup() {
// setup 执行顺序:
// 1. props 解析
// 2. setup() 执行 ← 当前位置
// 3. data/computed/methods 等选项处理
// 4. beforeCreate
// 5. created

console.log(this); // undefined

return {};
}
};

Composition API 设计上就不依赖 this,通过显式导入获取功能。

Q4: Composables 和 Hooks 有什么关系?

答案

Vue 的 Composables 受 React Hooks 启发,但有本质区别:

特性Vue ComposablesReact Hooks
执行次数只在 setup 时执行一次每次渲染都执行
依赖追踪自动(响应式系统)手动声明(deps 数组)
条件调用✅ 可以❌ 不可以
调用顺序不重要必须固定
// Vue:setup 只执行一次
setup() {
// 条件调用 OK
if (condition) {
useSomething();
}
}

// React:每次渲染都执行,顺序必须固定
function App() {
// ❌ 条件调用会报错
if (condition) {
useSomething(); // Error!
}
}

Q5: 如何从 Options API 迁移到 Composition API?

答案

  1. 渐进式迁移:不需要一次性全部迁移
// 步骤 1:添加 setup,逐步迁移逻辑
export default {
data() {
return { oldData: 'value' }; // 保留旧代码
},
setup() {
const newData = ref('value'); // 新代码
return { newData };
}
};

// 步骤 2:使用 script setup 重写
<script setup lang="ts">
const newData = ref('value');
const oldData = ref('value');
</script>
  1. 提取 Composables:将可复用逻辑提取为组合式函数
// 提取 mixin 为 composable
// 旧:mixins: [fetchMixin]
// 新:const { data, loading, error } = useFetch(url);

相关链接