最近刚用上 Vue3, 我在写 Vue3 的时候总感觉代码非常的散, 稍微复杂的页面里, 就是一堆的 const ref, computed, 更不用说一堆的 xxxLoading, xxxVisible, showXXX, hideXXX, 感觉写 Vue2 的时候也没这么乱过, 如果说要提取所谓 Composiable 组件, 感觉又是一堆的 useXXX, 导出一堆的 xxx,xxx 好像也没好到哪里去, 是我写的姿势不对吗? 这方面的最佳实践到底是什么, 有没有哪个开源项目让我参考参考?
![]() |
1
lepig 10 天前
vue3 相比 vue2 有什么优势的地方呢。
我一个后端 ,想直接学 vue2 不知现在是否是正确的选择。 就是看了 vue2 文档感觉相对简单好入门一点 |
2
lilu0826 10 天前
写习惯了就好,哈哈。 可以去看下 ElementPlus 组件库源码。
|
4
jeodeng 10 天前
你写 vue3 用的组合式 API 写法吧?
对于大型复杂项目来说,我觉得组合式 API 写法比较考验编写的个人能力,编写出可读性高的代码,不然很容易就乱了... 但由于团队的人员不同,而且水平不一,我推荐大型多人协作的项目用选项式 API 写法,相对来说可读性高点,便于团队协作维护。 如果是简单的小项目,组合式 API 写法确实快一些,而且方便。 |
5
xuxiake 10 天前
彻底拥抱 Composition API
|
![]() |
6
yozoh1163 10 天前
|
7
yesterdaysun OP 我也想彻底拥抱 Composition API, 奈何实力不够啊, 一开始用 Cursor AI 帮我提取复用, 结果也是整出来一坨看着就毫无美感的代码, 想想还是得找大佬的例子学习学习
|
![]() |
8
Immortal 10 天前
|
9
visper 10 天前 ![]() composition api 唯一的好处就是灵活吧。试下以这样的目标写代码:我这一块功能的代码都放在这里,如果不要这个功能直接把正块代码删除就行。不会影响其他功能。
|
![]() |
10
dfkjgklfdjg 10 天前 ![]() 是的,会有点乱。特别是在大组件的情况下。
其实原本的 options api 也会有这样的问题,只不过在外层用 data ,computed ,methods 之类的包了下可以折叠起来,所以在折叠的情况下,看起来会更 "整洁" 一些。 ----- 日常实际开发中逻辑复用的需求下会出现使用 mixins 和 extends 来混合代码的情况。 composition api 的出现就是想要避免原本的隐式缺陷。👉 [#为什么要有组合式 API ? - 组合式 API 常见问答 | Vue.js]( https://cn.vuejs.org/guide/extras/composition-api-faq.html#why-composition-api) 👇 所谓的整洁度其实也就是下面这样图这样,把相关联的业务逻辑放到一起来维护 ![]() 那么其实就是靠人的自觉来把相关的逻辑放到一起,如果没有开发规范或者一些约定,胡乱 Coding 就会出现混乱的感觉。 👉 [#约定和最佳实践 - 组合式函数 | Vue.js]( https://cn.vuejs.org/guide/reusability/composables#conventions-and-best-practices) 但其实可以把一些复杂逻辑的业务整理抽象成单独组合式函数,放到单独的 js, ts 文件中,在在业务组件中 import 进来使用。 比如说: ```js <script setup> import { useFeatureA } from './featureA.js' import { useFeatureB } from './featureB.js' import { useFeatureC } from './featureC.js' const { foo, bar } = useFeatureA() const { baz } = useFeatureB(foo) const { qux } = useFeatureC(baz) </script> ``` 我一般会推荐组员把 SFC 的代码行控制在 400~600 行以内(包含了模板),太过于复杂的就会建议他们按照 **容器组件** 和 **展示组件** 的思想拆分。 👉 [关于 React 的 Container&Presentational Component 模型结构分析 - Clark's Blog - SegmentFault 思否]( https://segmentfault.com/a/1190000007875199) |
11
momowei 10 天前
vue3 我用的挺爽的,比 react 我觉得更自然,除了 slot 这个天生的有点不方便没办法
|
![]() |
12
RogerL 10 天前 ![]() 我个人喜欢用 @tanstack/vue-query
代码基本是这个风格: const { data, isLoading, refetch, edit } = useCurrentUser() const { data: options } = useUserOptions() 基本上业务处理逻辑能扔的全扔到 hooks 里面 api 各种接口全都用 openapi-typescript 去生成类型声明,用 useQuery 去封装 常用库: es-toolkit @vueuse/core 常用 vite 插件: unplugin-auto-import unplugin-vue-components unplugin-vue-router |
13
gefangshuai 10 天前
乱不乱看个人,更容易封装了是真的
|
![]() |
14
9A0DIP9kgH1O4wjR 10 天前
感觉还是 vue2 用着爽一点。。。
|
![]() |
16
shintendo 10 天前 ![]() |
![]() |
17
bojackhorseman 10 天前
其实 vue3 开启 setup 后方便很多,vue2 的 option 写法从别处 import 一个函数还要挂载到 data 里才能在 template 里用,如果后来这个函数不用了,清理冗余代码也是一件头疼的事。
|
18
TimG 10 天前 via Android
我也是刚刚从 Vue2 切换到 Vue3 ,目前也是一头雾水。我想因为 Vue2 时代按照选项式已经写习惯了,即使换成 3 ,默认排序还是会不自觉按照类型去划分,而不是功能。到这一步,十分想要一个 C#的#region 块功能做代码块的功能注释,IDE 帮忙折叠代码块,这样会更好一些。
话说回来,控件的逻辑多了,即使 js 内部紧密,距离 div 还是十万八千里,个人感觉这种单个“重控件”不是一种很好的实践,不如尝试解耦,就像 16#说的那样。 |
![]() |
19
dfkjgklfdjg 10 天前
@shintendo #16 , 大部分人已经在日常开发中。已经按照自己的整洁偏好去整理了代码或者拆分了组件,所以没有什么感知。
如果你点开 Vue 关于这个图片介绍部分的仓库链接就能看到了。 👉 选项式 [vue-cli/packages/@vue/cli-ui/src/components/folder/FolderExplorer.vue at a09407dd5b9f18ace7501ddb603b95e31d6d93c0 · vuejs/vue-cli]( https://github.com/vuejs/vue-cli/blob/a09407dd5b9f18ace7501ddb603b95e31d6d93c0/packages/@vue/cli-ui/src/components/folder/FolderExplorer.vue#L198-L404) 👉 组合式 [docs-zh-cn/assets/FileExplorer.vue at main · vuejs-translations/docs-zh-cn]( https://github.com/vuejs-translations/docs-zh-cn/blob/main/assets/FileExplorer.vue) 其实和我们日常开发的代码结构没有什么差别。代码量其实也没有很大。 我个人没有什么感觉,但是 Options API 需要在 data ,computed ,methods 来回反复横跳已经被社区诟病很久了。 |
20
yesterdaysun OP @dfkjgklfdjg @shintendo 我对组合式这种集中业务逻辑的设计没有任何意见, 对于明显属于复用的代码, 可以分离成一个 Composable, 没有什么心智负担. 但是对于普通的业务组件, 就是一堆面条代码, 重要的不是复用, 而是切分组织不同功能点, 但是我对它的拆分管理的方法有疑问, 如果像图上这样, 一堆一堆的放在一起, 但是实际代码里面可没有这些颜色区分代码, 实际上就是一坨, 写多了自然就乱了. 我很想拆成不同文件, 但是就像前面说的, 之前尝试过有点失败, 分离成 useComposable 之后, 主页面就是一堆的{xxx,xxx,......}=userXXX 的代码, 括号里面可能一下子就是 8/9 个需要导出的参数, 看着就很累, 好像也不优雅.
所以在拆分业务逻辑或者拆分子组件这一块, 到底应该怎么做比较好? 或者说你们真的很喜欢那种 useXXX, 然后导出 8/9 个参数的写法? |
![]() |
21
dfkjgklfdjg 10 天前
@dfkjgklfdjg #19 ,其实 composition api 的优势并不是在于上面逻辑关注点导致的**整洁度**上面。而是在把逻辑关注点相关的代码被归为了一块完整的业务逻辑代码,可以很容易地将这一组代码抽象到外部 JS 文件中,来实现逻辑复用和拆分。以及函数组织代码所提供的更好的类型推导。
|
22
m319 10 天前
我的感觉是即使不考虑复用,只要内容稍多且能拆分就要尽量拆组件,控制单组件大小,组件稍稍一大,代码想不乱都难,只要组件小,不管怎么写始终都是比较可控的,无论是 vue2 vue3 还是 react 或者纯 js 都是,唯一的问题是目录结构就比较多了
|
![]() |
24
dfkjgklfdjg 10 天前
@yesterdaysun #20 ,面条代码之间可以用空行或者注释行来区分。但是如果是很复杂了的情况, 可以继续拆组件(比如说我在 #10 中提到的容器、展示组件的思想),或者单纯只是把业务逻辑提取出来,然后通过函数返回值的形式来调用就可以了,并不一定要改成 useXXX 这样的形式。
就是简单的函数返回: ```js async fcuntion fnA (X) { const valueB = fnB(XX) const fetchData = await fetchXXX() } function fnB(XXX) { .... return XXX } ``` 按照指责单一、关注点分离的思想去拆就可以了。至于是要在一个文件里面,还是拆分成多个文件就是看你自己的喜好。 ----- 一些需要改造成 useXXX 的,常用的其实基本上都可以在 [VueUse]( https://vueuse.org/) 这个库里面找到。 一些业务逻辑相关的,比如说 CURD 的管理页面就会抽象一个 useTable() 的 hooks 来使用。但是返回出来的变量也不一定都要使用,具体用到哪些就解构出来哪些就好了。如果按照你说的需要同时解出来 8 、9 个变量了。是不是应该考虑一下逻辑再拆分。 不确定是否是最优解的场景,我的想法是找比较大的开源项目是怎么设计的,比如说我提到的 useTable ,社区的解决方案中就是再组装之后返回的,把相关的一些属性用一个属性包起来 ```js export const useTable = (config: UseTableConfig) => { .... return { tableRegister: register, tableMethods: methods, tableState: { currentPage, pageSize, total, dataList, loading } } } ``` [vue-element-plus-admin/src/hooks/web/useTable.ts at v2.10.0 · kailong321200875/vue-element-plus-admin]( https://github.com/kailong321200875/vue-element-plus-admin/blob/v2.10.0/src/hooks/web/useTable.ts#L184) |
![]() |
25
UnluckyNinja 9 天前
优点是比较出来的,vue3 优点在于更灵活,具体怎么做取决于开发者,vue2 时代 options API 很多地方是强耦合的,响应系统严重依赖于组件实例,this here this there ,vue3 我都几乎没见过 this 了
迷茫时可以看看 VueUse ,Composable 的标杆 #20 > 或者说你们真的很喜欢那种 useXXX, 然后导出 8/9 个参数的写法? 先不说有没有必要都放在同一个 composable 里,觉得返回值用解构式声明太多你可以不写解构声明,就用 reactive 包起来,例如`const mouse = reactive(useMouse())`,也是官方推荐的写法 |
26
connection 9 天前
你这种问题是 composition api 的书写模式的问题吧,跟 vue 版本倒是关系不大,毕竟 vue3 也可以使用类组件书写
|
27
yesterdaysun OP 看了上面几位大佬的讲解稍微有点感觉了, 不过回到最开始的主题, 有没有那种可以学习的开源库? 最好是那种业务逻辑面条代码一堆的, 学习一下别人是怎么处理这种代码耦合分离的问题的, 上面列出的几个库主要是组件库之类的
|
![]() |
28
dfkjgklfdjg 9 天前
@yesterdaysun #27 ,我贴的是 Admin 框架,并不是 UI 库。里面有一些基础的通用页面,比如说用户管理、角色管理、菜单管理这种的,对于管理后台来说已经足够参考了。
如果要复杂的具体业务逻辑那么多半不会开源出来,如果是非管理后台的需求,可以直接在 Github 中用关键词 + Vue 的组合去检索,按照 star 数量来排序慢慢找就好了。 |
![]() |
29
txzh007 9 天前
vue3 写到最后肯定是 tsx 呀.
|
![]() |
30
Zzzz77 9 天前
你仍然可以沿用部分 Options API 的思维来写 Composition API
具体来说,你可以: 把 props 都写在一起( Options API 中的 data ) 把 ref 都写一起( Options API 中的 data ) 把 computed 都写在一起( Options API 中的 computed ) 把生命周期都写在一起( Options API 中的生命周期) 把 watch 都写在一起( Options API 中的 watch ) 把函数都写在一起( Options API 中的 methods ) 以此类推... 这样子在代码组织上,部分保留了 Options API 的思想,但是当你需要对一些逻辑进行封装时,又可以享受到 Composition API 的优越性(业务逻辑易抽象封装是 Vue3 相比 2 最大的提升,不需要再去写恶心的 mixin ) 可以参考我的项目: https://github.com/pipipi-pikachu/PPTist |
31
Cbdy 9 天前
一个文件的代码行数尽量不要超过 150 行
|
![]() |
33
ylsAGI PRO 现在写 vue3 的姿势是用 Nuxt3 框架,可以自动导入 Vue 函数/组件/路由等,专注写页面代码就行
|
![]() |
34
yafoo 9 天前 via Android
我也有这种感觉,所以,现在写 vue3 我还是用 options 的写法。不过页面太大时,options 写法也不好。
|
![]() |
36
sakitamFDD 9 天前
@TimG 佬想找的是否是这个,这种注释方式在 vsc 和 webstorm 目前应该都是支持的
```js //#region if (useArraySome([])){ } else{ } //#endregion ``` |
![]() |
37
flyinghigherair 9 天前
@Cbdy 非常赞同
|
38
TimG 9 天前 via Android
@sakitamFDD 确实是这种,没想到竟然真的有,太感谢了,明天就试试看。
|
![]() |
40
zcf0508 9 天前 via Android
|
![]() |
41
zcf0508 9 天前 via Android
|
![]() |
43
Terry05 9 天前
Composition API 最大的好处是可以更好组织和抽象,然而组织和抽象又需要经验和设计,觉得不好掌握可以考虑用回 Option API ,慢慢理解 Composition API 的优势
|
![]() |
44
beyondstars 9 天前
更快的交付和更好的交付。对于任何框架皆然。一个是快速做出来并且满足功能要求,二个是 bug 少然后后续好扩展、好维护。
|
![]() |
45
mizuhashi 9 天前
@yesterdaysun 你可以讓 composable 返回一個 reactive object ,例如
``` function useComposable() { const r = ref() const c = computed(() => xxx) return reactive({ r, c }) } const composable = useComposable() composable.c // 模板裏 ``` |
![]() |
46
starlion 9 天前
来学习下 vue3
|
![]() |
47
dream4ever 9 天前
@ylsAGI +1 ,Nuxt 很多功能开箱即用,挺省心的。
|
![]() |
48
ckvv 9 天前
|
![]() |
49
jenhe 9 天前
https://github.com/dirkhe1051931999/quasar-typescript-admin-template
小弟不才,斗胆推荐下我的写法,vue3+vue-facing-decorator+vuex-module-decorators |
![]() |
50
jenhe 9 天前
@jenhe #49
<template> <div class="fullscreen bg-blue text-white text-center q-pa-md flex flex-center"> <div> <div style="font-size: 30vh">404</div> <div class="text-h2" style="opacity: 0.4">Oops. Nothing here...</div> <q-btn class="q-mt-xl" color="white" text-color="blue" unelevated to="/dashboard" label="Go Home" /> </div> </div> </template> <script lang="ts"> import { Component, Vue } from 'vue-facing-decorator'; @Component({ name: 'myComponents404', }) export default class myComponents404 extends Vue { mounted() { this.$router.push('/dashboard'); } } </script> 自我感觉 class 方式写起来很舒服 |
![]() |
51
BeijingBaby 9 天前
最郁闷的是 vue3 和 vue2 完全就是 2 个不同的东西,没法相互兼容,很多老项目还在用 vue2 ,根本无法升级。
就因为这样弃掉 vue 的,新项目完全用 reactjs 了,毕竟到时候又弄个 vue4 不兼容 3 和 2 咋办。 |
52
Oliveira5 9 天前
有没有大佬推荐几个用 Vue3 写的好的库,想看一下大家的最佳实践
|
![]() |
53
jenhe 9 天前
|
55
Huelse 9 天前
composition api 不就是 react 的组织方式?
如果开发人员水平不够的话写什么都是一坨屎,换言之也能写得很好 |
56
pakholeung372 9 天前
@dfkjgklfdjg react 的容器和展示组件拆分现在看来是一个非常不好的实践,真实的业务往往有些代码不知道是放容器还是展示,导致实践起来很割裂,过度拆分还影响性能;现在完全可以用 hooks 来代替。简单来你要觉得处理数据的代码很多很杂,你就拆到 hook 里维护就好了
|
60
coolcoolxk 9 天前
@RogerL openapi-typescript 大佬这个东西是干嘛的?没太看明白呢
![]() |
![]() |
61
dfkjgklfdjg 9 天前
@pakholeung372 #56 ,并不是说完全按照这个标准去实施,按照容器和展示组件的理念在大组件的场景下作为拆分组件的指导。复杂的业务逻辑依旧可以把他们提取成单独的 TS 函数或者 Hooks 。
但是作为渲染的叶子节点组件,我觉得不要业务太多强相关逻辑是正确的,在容器组件把数据处理好传递下来就行了,我们需要确定数据会在哪些部分做哪些修改。如果是视图层的交互逻辑,没有必要区分的太清楚,我觉得主要是数据的组装和接口交互。 过度拆分和封装的问题,不一定是容器和展示组件导致的。这个是经验问题,在职业生涯的起步阶段必定会经历的过程。需要开发者自己知道为什么拆分会带来什么好处,而不是按部就班。 |
![]() |
62
gaigechunfeng 9 天前
没体会到 vue3 ,总觉得写起来很别扭。
项目不大,我又回退到 vue2 了。 管他呢, 写着爽才是真的爽。 vue2 也可以写的很有条理啊。 |
64
valkyrjaE 9 天前
最佳实践不好说,但是好实践肯定是 vibe 出来的预制菜,让他给你写页面写组件,跟着预制菜写写法就行了
|
![]() |
65
RogerL 9 天前
@coolcoolxk 根据后端接口文档生成 Typescript 类型声明文件的
后端接口文档一般都是 Swagger 这种遵循 OpenAPI 规范的,用这个就不用自己定义数据类型,跟后端接口数据格式保持同步 这样你在开发的时候因为有类型声明,写起来更容易 用这个的前提是你们后端 API 文档写的规范,并且前端项目也是 TypeScript 规范,不是到处用 any |
![]() |
66
jy02534655 9 天前
我写组合式 api 是先按最小化原则和功能场景来写的,比如表单这块就定义一个 compositionFormBase ,弹窗就是 compositionDialogBase ,表单+弹窗就把他们组合起来构成 compositionDialogForm ,每个场景块拆到最小,然后根据日常场景组合,用的时候就比较灵活
|
![]() |
67
RogerL 9 天前
|
68
sakura1988 9 天前
vue 的 composable 和 react 的 hook 一样,都能用于实现 headless component ,将 state 和 logic 与 UI 解耦
|
![]() |
69
bojue 9 天前
我感觉主要是拆分模块封装,vue3 看着文档写着改着写了项目:
https://github.com/bojue/lemon-form 但是一般会把组件封装起来 1. 项目 [组件] : https://github.com/bojue/lemon-form/tree/master/src/components 2. Form 表单 [元素组件] : https://github.com/bojue/lemon-form/tree/master/src/components-form 3. Form 表单 [设置组件] : https://github.com/bojue/lemon-form/tree/master/src/components-form-setting 每行代码不代表最佳实践,整体感觉维护成本很低 |
![]() |
70
duanxianze 9 天前
你说的大部分问题并不是 vue3 独有的,任何 ui 开发都会有你说的这些问题,vue3 的好处就是你可以精细化的控制粒度,每一个函数每一个组件都单独引入导出,也可以啥都一把梭,混到一起也没关系,就我个人而言,业务逻辑不用太在意,保持一个最低水平的控制就好了,如果要开发基础类库,再去考虑最佳实践之类的
|
71
coolcoolxk 9 天前
@RogerL #67 感谢大佬
|
72
kakki 9 天前
最佳实践? 就是换成 React
|
![]() |
73
ruoxie 9 天前
https://juejin.cn/post/7139497477086019621 已经落地了多个项目的实践
|
![]() |
74
bojackhorseman 9 天前
@BeijingBaby vue2.7 可以兼容两种写法,虽然会让项目看起来更💩了,但如果你只用组合 API 就可以了。
|
75
cfancc 9 天前
所以我还是喜欢 vue2 的写法,vue3 被 react 带偏了。这么一大堆东西,是逼着你往外拆分,拆费时间,不拆就乱。
|
76
C293943 8 天前
react 写个子组件导出出去,vue3 写个子组件等别处引入,我用 react 点击函数名就能直接查看当前的函数组件谁在用,vue3 有这个吗?我有时就觉得,固定的 template ,script ,style 区域跟 optionsAPI 也没区别,还拉长格式化后的行数
|
77
lamzhongxian 8 天前
个人感觉 vue3 对比 vue2 最大的爽点就是可以在 vue 文件之外定义响应式变量,按照逻辑拆分代码,封装 hooks ,hooks 里面 ref 数据源->computed 显示数据->watch 数据源做相关逻辑,这样一条数据链路写下来代码逻辑就很清晰了,然后在 vue 文件里面引入和组合 hooks ,这样单个 vue 文件就很整洁,要做修改就只需跳转到对应的 hooks 里面改就可以了,比起 vue2 那种在一个文件里疯狂滚动找逻辑要舒服多了
|
![]() |
78
bowencool 8 天前
写状态不是跟写变量一样吗?怎么把相关的逻辑/状态/变量一起抽象封装掉才是编程能力的体现,只知道复制粘贴,不会抽象/封装的话,写啥都一样的,最后都是一地鸡毛。甚至你用别人封装好的也是一种进步。
另外,Composition API 对标 React Hooks ,明明让“封装”这件事更极致了,从组件层面进一步细化到逻辑层面。而且还改进了不少:没有闭包问题,可以在判断条件下执行... |
79
zsxeee 8 天前 via Android
我感觉 options api 会给人一种自己已经整理了代码的错觉。因为它的分类依据完全是根据数据类型来的,强制你以一种没有负担的方式“分类”了。compose api 确实能做到更好的整洁性,但是代价是需要额外耗费心智来想怎么分类、抽离逻辑,这样开发在对于不熟悉或者没有这方面经验的人来说写着可能有些痛苦。毕竟之前自己只需要根据下意识的数据流逻辑顺着写下去就好了,现在没了 options api 的“整理结构”,即使写一些不大的组件自己也会很容易的察觉到代码乱需要整理,而这时候只能自己想办法整理了。
|
![]() |
80
pytth 8 天前 via Android
没办法,vue3 的写法就是一堆 const ,一堆 ref ,一堆 return 。
|