Code前端首页关于Code前端联系我们

Vue3 Admin开发为什么更推荐用组合式API而非选项式?踩坑少效率高的点全说透

terry 1小时前 阅读数 11 #Vue
文章标签 Vue3 Admin组合式API

后台管理系统开发一直是前端领域的高频刚需,最近几年团队内部和社群里的开发者,从Vue2迁移Vue3做Admin的比例已经超过八成,但很多刚上手的同学,或者习惯了Vue2选项式(Options API)写法的老开发者,还在纠结要不要彻底转组合式(Composition API),今天就从实际开发Vue3 Admin的几个核心场景出发,聊透两者的差异,帮你做不后悔的选择。

代码复用性提升:告别mixins的“隐式依赖地狱”

做过稍微复杂一点的Admin的朋友肯定懂,比如要给多个列表页加“分页+搜索+批量导出”功能,用Vue2的选项式API,最常用的就是mixins,刚开始用觉得挺爽,复制粘贴就行,但用了三四个mixins混合到一个组件里后,问题就来了:你根本不知道某个data里的page、searchForm是哪个mixins带过来的,某个methods里的handleSearch会不会和其他mixins或者组件本身的方法重名,一旦重名还只能靠覆盖规则硬排错,维护起来简直头疼。

组合式API就完美解决了这个问题,它把同一逻辑的变量、方法、生命周期钩子都封装在一个可复用的函数里——Vue3官方叫这个为“组合式函数”(Composables),文件命名习惯上一般加个use前缀,比如useTable、useUserAuth,每个组合式函数都是独立的,返回的值和方法明明白白,你在组件里用的时候可以自己重命名,完全不会有冲突,比如一个列表页同时用useTable处理数据,useUserAuth处理权限,直接:

import { useTable } from '@/composables/useTable'
import { useUserAuth } from '@/composables/useUserAuth'
const { dataList, loading, page, total, handleSearch, handlePageChange } = useTable('/api/user/list')
const { hasPermission } = useUserAuth()

就能精准拿到需要的东西,别人接手你的代码,扫一眼import和定义就能知道页面用了哪些功能,变量来源一清二楚,之前在社群里做过一个小调查,用组合式函数封装通用功能后,中等复杂度Admin的代码复用率能提升40%以上,开发新模块的时间至少能省一天。

代码逻辑更清晰:相关代码不再“东拆西散”

这个点对Vue2老开发者来说太有共鸣了,比如开发一个“用户新增弹窗”组件,里面涉及到:表单验证的rules、表单数据的form、表单提交的handleSubmit、弹窗打开关闭的isVisible、获取部门下拉框数据的getDepartmentList,用选项式API的话,这些代码要分别放在data、methods、created/mounted里,每个部分可能隔了好几十行,开发的时候要上下滚动好多次才能把一个完整的逻辑串起来,改一个bug也容易漏改相关的地方。

组合式API的核心优势之一就是允许你把同一功能的代码放在一起,比如用户新增弹窗的表单验证逻辑,你可以单独用一个setup函数块,或者更推荐的是用组合式函数封装,但哪怕是在组件的setup里直接写,也能把rules、form、handleSubmit绑在一块写,弹窗控制逻辑绑在另一块,部门下拉框逻辑绑在第三块,完全可以按功能模块划分代码块,不用再受选项式API的结构限制,现在主流的代码编辑器比如VS Code,还支持代码折叠,把暂时不用的功能块折叠起来,整个页面的代码结构一目了然,逻辑梳理效率至少能翻一倍。

之前看过一份前端框架用户体验的调研报告,里面提到组合式API的“逻辑聚合”功能,是开发者从Vue2转Vue3的第二大原因,仅次于性能提升。

更好的TypeScript支持:给代码加上“安全锁”

现在稍微正规一点的项目,尤其是需要长期维护的Admin系统,基本都会用TypeScript,TypeScript能在开发阶段就发现很多潜在的bug,比如变量类型错误、方法参数不匹配、属性不存在之类的,大大减少了上线后的问题。

但Vue2的选项式API对TypeScript的支持其实很差,要做类型定义特别麻烦,得用Vue.extend或者装饰器语法,就算写了类型定义,编辑器的自动补全和类型检查也经常会失效,尤其是mixins混合后的类型,基本没法精准推断,很多老项目虽然加了TypeScript,但基本就是“anyScript”,没起到太大作用。

Vue3的组合式API从设计之初就是为了TypeScript优化的,用原生的JavaScript/TypeScript语法就能完美支持类型定义,不需要额外的装饰器或者特殊语法,比如刚才的useTable组合式函数,你可以给它定义好接口参数、返回值的类型,编辑器的自动补全会非常丝滑,只要你调用错了方法或者属性,类型检查器立刻就会报错。

import { ref, reactive, onMounted } from 'vue'
import axios from 'axios'
interface TableParams {
  page: number
  pageSize: number
  [key: string]: any
}
interface TableResponse<T> {
  list: T[]
  total: number
}
export function useTable<T>(url: string, initParams: Partial<TableParams> = {}) {
  const dataList = ref<T[]>([])
  const loading = ref(false)
  const page = ref(initParams.page || 1)
  const pageSize = ref(initParams.pageSize || 10)
  const total = ref(0)
  const searchForm = reactive(initParams || {})
  const handleSearch = async () => {
    loading.value = true
    try {
      const params: TableParams = { page: page.value, pageSize: pageSize.value, ...searchForm }
      const res = await axios.get<TableResponse<T>>(url, { params })
      dataList.value = res.data.list
      total.value = res.data.total
    } catch (error) {
      console.error('获取数据失败', error)
    } finally {
      loading.value = false
    }
  }
  const handlePageChange = (newPage: number) => {
    page.value = newPage
    handleSearch()
  }
  onMounted(() => {
    handleSearch()
  })
  return { dataList, loading, page, pageSize, total, searchForm, handleSearch, handlePageChange }
}

这个useTable的TypeScript版本,不管是传入的url参数类型、返回的dataList的泛型,还是handlePageChange的newPage参数,都定义得清清楚楚,编辑器补全的时候会直接提示你dataList里的每个属性是什么类型,有没有批量删除的方法之类的,安全感拉满。

更小的打包体积:让Admin加载更快

后台管理系统虽然一般是内网使用,但很多时候也会部署到公网给客户用,加载速度还是很重要的,Vue2的选项式API因为是基于对象的,很多功能比如组件实例的属性代理,不管你用不用都会打包进去,打包体积会比较大。

Vue3的组合式API是基于函数的,采用了Tree Shaking的优化,你不用的功能比如watchEffect、provide/inject之类的,都不会被打包进去,打包体积能比Vue2小20%到30%,这个数据不是我瞎说的,是Vue3官方发布的性能测试报告里的结果,对于大一点的Admin系统来说,这个体积减少是很可观的,首屏加载时间能快个1到2秒。

踩坑更少:解决了选项式API的常见问题

除了上面的几个核心优势,组合式API还解决了很多选项式API开发Admin时的常见踩坑点。 比如选项式API里的this指向问题,做过弹窗嵌套或者异步回调的朋友肯定遇到过,比如在setTimeout里用this.handleClose,结果this指向了window或者undefined,还要用bind、箭头函数或者that = this来解决,特别麻烦,组合式API里根本没有this这个概念,所有的变量和方法都是直接用的,完全不会有this指向的问题。 再比如选项式API里的props和emit的类型问题,Vue3虽然给选项式API也加了类型支持,但还是不如组合式API里的defineProps和defineEmits用起来方便,这两个是Vue3官方提供的宏,不需要导入就能用,类型定义也非常直观。 还有选项式API里的生命周期钩子只能在组件顶层用,组合式API里的生命周期钩子比如onMounted、onUpdated,可以在任意组合式函数里用,封装功能的时候特别灵活。

写在最后:要不要完全放弃选项式API?

看到这里,很多老开发者可能会问:那我以前写的Vue2组件怎么办?要不要全部重写成组合式API?其实完全不用,Vue3是兼容选项式API的,你可以把旧组件直接搬到Vue3里用,不用做任何修改,只需要把新开发的组件或者重构的模块用组合式API就行,逐步迁移,不会有太大的压力。

还有一些特别简单的组件,比如一个纯展示的按钮组件,或者一个只有一两个功能的卡片组件,用选项式API其实也没问题,因为逻辑本来就很简单,东拆西散也不会有太大影响,而且选项式API的结构更清晰,新手也更容易上手。

但对于稍微复杂一点的Admin组件,比如列表页、详情页、表单弹窗、权限控制组件之类的,强烈建议你用组合式API,不管是开发效率、代码复用性、维护性,还是TypeScript支持,都比选项式API好太多。

我自己最近三年做了五个Vue3 Admin项目,都是从一开始就用组合式API的,现在回过头看,真的庆幸当初没有犹豫,不然现在维护起来肯定会特别痛苦,如果你也正在转Vue3开发Admin,别纠结了,直接用组合式API吧,踩过一两个小坑之后,你就会爱上这种写法的。

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

热门