uni-app 从 Options API 迁移到 Composition API 的详细指南
一、迁移前的准备
-
升级环境:
- 确保 HBuilderX 版本 ≥ 3.2.0
- 项目 uni-app 版本 ≥ 3.0.0
-
了解 Composition API 基础:
- 响应式系统:
ref
、reactive
- 生命周期钩子:
onMounted
、onUnload
等 - 组合函数:提取可复用逻辑
- 响应式系统:
-
备份项目:
- 迁移前务必备份代码
- 建议使用版本控制系统(如 Git)
二、渐进式迁移策略
-
组件级别迁移:
- 先迁移简单、独立的组件
- 再处理复杂、依赖多的组件
-
功能模块迁移:
- 先迁移数据逻辑
- 再迁移生命周期钩子
- 最后处理计算属性和监听器
-
保持两种 API 并存:
- 迁移期间允许两种 API 在项目中共存
- 新组件使用 Composition API,旧组件逐步迁移
三、基础语法迁移
1. 数据定义
javascript
// Options API
export default {
data() {
return {
count: 0,
user: {
name: 'John',
age: 30
}
};
}
}
// Composition API
import { ref, reactive } from 'vue';
export default {
setup() {
// 基本类型用 ref
const count = ref(0);
// 对象用 reactive
const user = reactive({
name: 'John',
age: 30
});
return {
count,
user
};
}
}
2. 方法定义
javascript
// Options API
export default {
methods: {
increment() {
this.count++;
}
}
}
// Composition API
import { ref } from 'vue';
export default {
setup() {
const count = ref(0);
const increment = () => {
count.value++;
};
return {
count,
increment
};
}
}
3. 计算属性
javascript
// Options API
export default {
computed: {
doubleCount() {
return this.count * 2;
}
}
}
// Composition API
import { ref, computed } from 'vue';
export default {
setup() {
const count = ref(0);
const doubleCount = computed(() => count.value * 2);
return {
count,
doubleCount
};
}
}
4. 监听器
javascript
// Options API
export default {
watch: {
count(newVal, oldVal) {
console.log('count changed:', newVal, oldVal);
}
}
}
// Composition API
import { ref, watch } from 'vue';
export default {
setup() {
const count = ref(0);
watch(count, (newVal, oldVal) => {
console.log('count changed:', newVal, oldVal);
});
return {
count
};
}
}
四、生命周期钩子迁移
javascript
// Options API
export default {
onLoad() {
console.log('页面加载');
},
onShow() {
console.log('页面显示');
},
onUnload() {
console.log('页面卸载');
}
}
// Composition API
import { onLoad, onShow, onUnload } from 'vue';
export default {
setup() {
onLoad(() => {
console.log('页面加载');
});
onShow(() => {
console.log('页面显示');
});
onUnload(() => {
console.log('页面卸载');
});
return {};
}
}
五、组合函数提取复用逻辑
javascript
// Options API (mixins)
const counterMixin = {
data() {
return {
count: 0
};
},
methods: {
increment() {
this.count++;
}
}
};
export default {
mixins: [counterMixin]
}
// Composition API (组合函数)
// useCounter.js
import { ref } from 'vue';
export function useCounter(initialValue = 0) {
const count = ref(initialValue);
const increment = () => {
count.value++;
};
return {
count,
increment
};
}
// 组件中使用
import { useCounter } from './useCounter';
export default {
setup() {
const { count, increment } = useCounter(5);
return {
count,
increment
};
}
}
六、使用 <script setup>
简化语法
vue
<template>
<view>
<text>{{ count }}</text>
<button @click="increment">+1</button>
</view>
</template>
<script setup>
import { ref, onLoad } from 'vue';
// 响应式数据
const count = ref(0);
// 方法
const increment = () => {
count.value++;
};
// 生命周期钩子
onLoad(() => {
console.log('页面加载');
});
</script>
七、处理组件通信
1. Props
javascript
// Options API
export default {
props: {
message: String
},
methods: {
handleClick() {
console.log(this.message);
}
}
}
// Composition API
import { defineProps } from 'vue';
export default {
props: {
message: String
},
setup(props) {
const handleClick = () => {
console.log(props.message);
};
return {
handleClick
};
}
}
// 或使用 <script setup>
<script setup>
const props = defineProps({
message: String
});
const handleClick = () => {
console.log(props.message);
};
</script>
2. Emits
javascript
// Options API
export default {
emits: ['update'],
methods: {
triggerUpdate() {
this.$emit('update', 'new value');
}
}
}
// Composition API
import { defineEmits } from 'vue';
export default {
emits: ['update'],
setup(props, { emit }) {
const triggerUpdate = () => {
emit('update', 'new value');
};
return {
triggerUpdate
};
}
}
// 或使用 <script setup>
<script setup>
const emit = defineEmits(['update']);
const triggerUpdate = () => {
emit('update', 'new value');
};
</script>
八、处理特殊情况
1. 访问实例属性
javascript
// Options API
export default {
methods: {
callMethod() {
this.$refs.myRef.focus();
}
}
}
// Composition API
import { getCurrentInstance } from 'vue';
export default {
setup() {
const { proxy } = getCurrentInstance();
const callMethod = () => {
proxy.$refs.myRef.focus();
};
return {
callMethod
};
}
}
2. 处理 ref
javascript
// Options API
export default {
mounted() {
this.$refs.myRef.focus();
}
}
// Composition API
import { ref, onMounted } from 'vue';
export default {
setup() {
const myRef = ref(null);
onMounted(() => {
myRef.value.focus();
});
return {
myRef
};
}
}
九、测试与验证
-
单元测试:
- 确保迁移后的组件行为不变
- 使用 Vue Test Utils 3.0+ 测试 Composition API
-
集成测试:
- 验证组件间交互正常
- 测试路由、状态管理等集成功能
-
性能测试:
- 对比迁移前后的内存使用
- 验证响应式系统性能
十、迁移建议
-
从简单组件开始:
- 先迁移无依赖的基础组件
- 再迁移复杂业务组件
-
利用工具辅助:
- 使用 IDE 插件(如 Vetur)提供的代码转换功能
- 参考 Vue 官方迁移工具
-
团队培训:
- 组织 Composition API 培训
- 编写内部迁移指南和最佳实践
-
持续重构:
- 新功能优先使用 Composition API
- 逐步重构旧组件
总结
从 Options API 迁移到 Composition API 是一个渐进的过程,需要耐心和规划。建议采用"组件级别迁移"和"功能模块迁移"相结合的策略,先易后难,逐步推进。在迁移过程中,充分利用 Composition API 的优势,如逻辑复用、更好的 TypeScript 支持等,提高代码质量和可维护性。