关键在于渐进替换而非重写,从单个基础组件开始,用setup替代选项式API,将data转ref/reactive、methods移入setup、computed/watch改用函数、生命周期加on前缀,并适配响应式差异、抽离组合函数、启用兼容模式过渡。

直接用组合式 API 重构 Vue2 项目,关键不是“重写”,而是“渐进替换”——保留原有结构和逻辑边界,按组件粒度逐步抽离、封装、验证。核心在于理解响应式系统变化带来的行为差异,并让新旧逻辑共存过渡。
从单个组件开始,用 setup 替代选项式结构
选一个逻辑清晰、依赖少的基础组件(如按钮、表单项),不改动模板和业务逻辑,只改 script 部分:
- 把 data 中的字段转为
ref或reactive:简单值用ref(如count = ref(0)),对象用reactive(如form = reactive({ name: '', age: null })) - 把 methods 中的方法移到 setup 内,保持调用方式一致(注意
ref要通过.value修改) - 把 computed 和 watch 改用对应函数:如
computed(() => count.value * 2)、watch(() => props.id, fetchUser) - 生命周期钩子全部加
on前缀:onMounted、onUpdated、onBeforeUnmount
处理响应式行为差异,避免运行时异常
Vue3 的 Proxy 响应式机制和 Vue2 的 defineProperty 行为不同,老代码中常见几类“隐形坑”需主动适配:
-
数组索引赋值:Vue2 中
list[1] = newItem不触发更新,需用Vue.set;Vue3 中可直接赋值,无需额外操作 -
动态新增属性:Vue2 中
this.obj.newKey = val不响应;Vue3 中直接赋值即生效(前提是该对象本身是reactive创建的) -
嵌套对象监听:若 data 中返回的是普通对象(非 reactive 包裹),其深层属性修改不会触发更新;迁移时需显式用
reactive包裹整个结构 -
watch 监听数组长度:Vue2 支持
watch: { 'list.length': ... };Vue3 不再支持路径字符串监听,应改用watch(() => list.length, ...)
复用逻辑抽离为组合函数,统一管理跨组件状态
将老项目中常见的 mixin 或公共方法(如表单校验、列表分页、请求封装)提取成独立的组合函数(composable),例如:
使用 `@ainative/vue-sdk` 为 Vue 3 应用添加 AI 聊天功能。适用于以下场景:(1) 安装 `@ainative/vue-sdk`,(2) 在 Vue 组件中使用 `useChat` 组合式函数,(3) 提供……
立即学习“前端免费学习笔记(深入)”;
- 新建
useForm.js,导出useForm(initialData),内部用reactive管理表单数据,用computed暴露校验状态 - 新建
useList.js,封装fetchList、loading、pageInfo和watch重载逻辑 - 在组件中导入并调用:
const { form, validate } = useForm({ name: '' }),返回值可直接在模板中使用
这样既消除 mixin 命名冲突风险,又提升类型推断准确性,也为后续 TypeScript 升级打下基础。
保留兼容层,支撑混合开发过渡期
大型项目无法一次性全量切换,建议启用 Vue 官方兼容模式(@vue/compat)作为缓冲:
- 安装
@vue/compat并配置 alias:vue$: '@vue/compat' - 设置
compatConfig: { MODE: 2 }启用完全兼容模式,让大部分 Vue2 语法(如slot="name"、v-on.native)继续可用 - 初期开启
MODE: 3获取详细警告,快速定位待修复点,再逐个收敛 - 配合
defineComponent显式声明组件,避免 setup 中 this 误用,也利于 IDE 类型提示
等 70% 以上组件完成重构后,再移除兼容层,彻底切换到纯 Vue3 运行时。

















