一文理清在 vue2.x 中 compositionAPI 与 optionsAPI 混合使用要点

由于项目基于 vue2 框架,随着项目规模的增加,mixin 的组织方式越来越不方便维护,因此将其升级到 vue2.7,使用 composition API 与 options API 混合开发。

本文将一步一步梳理混合开发的步骤及要点,让大家对混合开发有一个全局的掌握。

向后移植的功能

  1. Composition API
  2. SFC <script setup>
  3. SFC CSS v-bind
  4. defineComponent():具有改进的类型推断(与Vue.extend相比)
  5. h()、useSlot()、useAttrs()、useCssModules()
  6. set()、del()nextTick() 在 ESM 构建中也作为命名导出提供
  7. 支持 emits,但仅用作类型检查用途(不影响运行时行为)。
  8. Vue2.7 还支持在模板表达式中使用 ESNext 语法
  9. 在模版里面用可选链,如formData?.userInfo?.userId

关于被导出的 API 的注意事项

  • 在 ESM 构建版本中,这些 API 会 (且仅会) 被导出为具名 API:

    1
    2
    3
    import 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
2
html复制代码// 在2.7中可行,在3.x中不可行
reactive(foo) === foo
  • 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 种情况讨论:

  1. 若修改原来的功能,建议直接使用选项式 API 的方式开发,因为在 setup 中无法获取到 this,无法调用一些现有的 data、methods 等等。
  2. 若新增加功能且与现有功能不耦合,可以直接添加 setup() 函数,在该函数中增加新功能逻辑。当然,若有多个功能,可以将功能拆分成多个文件,然后在 setup() 函数中来聚合
  3. 若开发新组件,可以直接使用 <script setup> 的方式

开发需知

  1. reactive()、ref()、shallowReactive() 将直接转换原始对象而不是创建代理

  2. 使用组件时,不要使用自闭合标签,应 <component></component>

  3. 对于数组,使用 ref,不要使用 reactive

refreactive

  • reactive 一般用于对象/数组类型的数据,都不需要使用 .value
  • ref一般用于基础数据类型的数据,在 JS 中读取和修改时,需要使用 .value,在模版中使用时则不需要;
  • reactive 可以修改深层属性值,并保持响应;
  • reactive 返回值和源对象不同;
  • reactive的属性值可以是 ref值;
  • ref 本质也是 reactiveref(obj)等价于 reactive({value: obj})

参考

本文参考以下文章,在此报以诚挚谢意!

  1. Vue 2.7 "Naruto" Released | The Vue Point (vuejs.org)

  2. 迁移至 Vue 2.7 — Vue.js (vuejs.org)

  3. Vue2.7正式发布,终于可以在Vue2项目中使用Vue3的特性了 - 掘金 (juejin.cn)