一文理清在 vue2.x 中 compositionAPI 与 optionsAPI 混合使用要点
由于项目基于 vue2 框架,随着项目规模的增加,mixin 的组织方式越来越不方便维护,因此将其升级到 vue2.7,使用 composition API 与 options API 混合开发。
本文将一步一步梳理混合开发的步骤及要点,让大家对混合开发有一个全局的掌握。
向后移植的功能
- Composition API
- SFC
<script setup>
- SFC CSS v-bind
defineComponent()
:具有改进的类型推断(与Vue.extend相比)h()、useSlot()、useAttrs()、useCssModules()
set()、del()
和nextTick()
在 ESM 构建中也作为命名导出提供- 支持
emits
,但仅用作类型检查用途(不影响运行时行为)。 - Vue2.7 还支持在模板表达式中使用 ESNext 语法
- 在模版里面用可选链,如
formData?.userInfo?.userId
关于被导出的 API 的注意事项
在 ESM 构建版本中,这些 API 会 (且仅会) 被导出为具名 API:
1
2
3import Vue, { ref } from "vue";
Vue.ref; // undefined,请换为使用具名导出的 API在 UMD 和 CJS 构建版本里,这些 API 会被导出为全局对象
Vue
的属性。当调用外置的 CJS 版本进行打包时,打包工具应该有能力处理与 ESM 模块的互操作 (ESM interop)。
与 Vue3 的差异
Composition API 使用 Vue2 的基于 getter/setter 的响应式系统进行反向移植,以确保浏览器兼容性。这意味着与 Vue3 的基于 proxy 的系统存在一些重要的行为差异:
- 所有 Vue2 更改检测警告仍然适用;
- reactive()、ref() 和 shallowReactive() 将直接转换原始对象而不是创建代理:
1 | html复制代码// 在2.7中可行,在3.x中不可行 |
- readonly() 确实创建了一个单独的对象,但它不会跟踪新添加的属性并且不适用于数组;
- 避免在 reactive() 中使用数组作为 root 值,因为如果没有属性访问,则不会跟踪数组的变化(这将导致警告);
- Reactivity APIs 忽略带有 symbol 键的属性。
此外,以下功能是未移植的:
- ❌ createApp()(Vue2 没有独立的应用范围)
- ❌ 在
<script setup>
顶层使用await
(Vue 2 不支持异步组件初始化) - ❌ 模板表达式中的 TypeScript 语法(与 Vue2 解析器不兼容)
- ❌ Reactivity transform(仍处于试验阶段)
- ❌ options 组件不支持 expose
选项(但在
<script setup>
中支持defineExpose()
)
vue2.x 升级为 vue2.7
请查看官方升级文档 升级指南
如何在vue2.x项目中使用 compositionAPI
适用场景
当将 vue2.x 升级到 vue2.7 后,有时候需要维护原来的组件,分 3 种情况讨论:
- 若修改原来的功能,建议直接使用选项式 API 的方式开发,因为在
setup
中无法获取到this
,无法调用一些现有的 data、methods 等等。 - 若新增加功能且与现有功能不耦合,可以直接添加
setup()
函数,在该函数中增加新功能逻辑。当然,若有多个功能,可以将功能拆分成多个文件,然后在setup()
函数中来聚合 - 若开发新组件,可以直接使用
<script setup>
的方式
开发需知
reactive()、ref()、shallowReactive()
将直接转换原始对象而不是创建代理使用组件时,不要使用自闭合标签,应
<component></component>
对于数组,使用
ref
,不要使用reactive
ref
与 reactive
reactive
一般用于对象/数组类型的数据,都不需要使用.value
;ref
一般用于基础数据类型的数据,在 JS 中读取和修改时,需要使用.value
,在模版中使用时则不需要;reactive
可以修改深层属性值,并保持响应;reactive
返回值和源对象不同;reactive
的属性值可以是ref
值;ref
本质也是reactive
,ref(obj)
等价于reactive({value: obj})
。
参考
本文参考以下文章,在此报以诚挚谢意!