. 在模板语法下这则是个不那么容易的事情,因此我们通常在 Vue 中传递组件 (Component) 而非元素 (Element)。对于 React 中的 <Button icon={<XxxIcon />}>
在 Vue 中的同类写法常常是 <Button :icon=\\"XxxIcon\\">
,其中传入组件而非元素——假如这里我们需要传入 <Icon icon=\\"carbon:home\\" />
这样的元素,Vue 这边就要复杂一些,变成了 <Button :icon=\\"defineComponent({ render: () => h(Icon, { icon: \'carbon:home\' }) })\\">
,为了避免这种难绷的语法,在大多数地方其实我们会使用 Slot 以及 Named slot 替代,基于模板的思路大多有这个问题。除此之外,模板也使 Vue 需要引入 <component is>
来解决在 JSX 不存在的问题。当然,这些都不是 Vue 的问题,只是模板的局限性,Vue 用 JSX 一样可以按我说的 React 组件库的那种思路写,Element Plus 的一些新组件就是这个思路。
模板显然也有自己的优点,很难说 JSX 和模板谁更优越。模板允许框架塞进更多自己提供的语法糖,在很大程度上也能使代码变得更加简洁,同时也使编译器优化变得更容易——对于组件库开发等场景来说,它可能稍微少了点灵活性,但对于应用开发已经足够优秀,并没有比 JSX 缺少什么。就我个人而言,我是更倾向于 JSX 的语法的,更方便在一个文件里封装多个小组件,但我对模板也没什么恶感。
还有个对多数人可能没什么感知,但对我而言感知明显的模板的问题——对 TS 的支持问题。平心而论,Vue 3.4 之后对 TS 基本上已经达到了完全的支持,但在一些边界的类型体操推导上仍存在一些问题,而且估摸着也很难在未来的版本中去支持,比如 defineProps
对条件类型的支持问题。 我在 VSCode 使用 Volar(现在叫 Vue - Official)插件时也经常遇到 TS 抽风问题,并且 ESLint 在 Vue SFC 中对 TS 的解析常常出问题,如开启 @typescript-eslint/recommended-type-check
后经常在 SFC 中给我解析出 any
,但 Volar 却能正常提示类型,我暂时没寻思出来这是 vue-eslint-parser 本来就有的问题还是我哪边配置不对,或者是 Volar 的问题。并且我始终不知道该如何让 Vue 在模板里给未知 tag 的 element 报错而不是推导为 unknown——vue-eslint-plugin 有这个选项,但不支持全局组件,对我来说确实没法用。
基于模板的 UI 框架大多有这个缺点——对于开发来说,它们对 TS 的支持通常限于大致能用而不太考虑优先支持复杂类型体操的解析。Vue 在 TS 支持方面其实已经做得很不错了,Svelte 用过几次,那边对 TS 的支持可以说就完全是“凑合能用”水平了。而 JSX 由于 TS 的内置支持则在类型安全上具有更好的表现,这个优点也是客观存在的。
说了这么多 React,并且似乎有些跑偏了,再回头谈谈 Vue. 要谈 Vue,显然要从 Vue 2 的 Options API 谈起。我至今仍觉得 Options API 有不少可取之处,最大的一点就是其极低的入门门槛和极其直观的语法——对于简单的业务页面开发,Options API 很少需要担心解构和丢失响应性的问题,一切都绑定在 this
上,默认更新 this
上的数据就能看到响应性的变化,心智负担其实是很低的。当然,this
经常因其迷惑特性而被诟病,以至于现在新库开发都不那么倾向于使用 class,但这不是个很难解决的问题,只需要把原先 { ... }
形式的组件定义改成 component((self) => ({ ... }))
就可以解决了——以一个作为参数传入的 self
替代 this
.
Options API 对 TS 其实也有不错的兼容性,即使使用 Vue 2.6,也可以安装 @vue/composition-api
在组件定义外边包上 defineComponent
以获得 this
上的类型提示。同时 Options API 也提供了一个最低限度的约束,data
、Lifecycle、computed
、methods
等必须分门别类放好写在一起,不允许杂七杂八东写一块西写一块——这种强制将可能在功能上相关的 data
、computed
、methods
拆分开来的做法可能在老手看来不那么理想,但至少强硬地避免新手将功能和逻辑上都毫无关联的部分胡乱摆放在一起,而这很大程度上也是 React 新手的普遍问题。我很相信 Options API 这些或许是“无意之间”保证代码维持了最低限度整洁性(易读性)和易上手特性(心智负担较低)的特点使 Vue 在 Vue 2 时代于国内被大量使用,并且直到今天大量国内项目还是没有要升级到 Vue 3 的意思,甚至新项目仍用 Vue 2——平心而论,Vue 3 确实不会给这其中很多新项目带来好处,自然也没有升级的必要。
Options API 到底有没有问题,Composition API 是否真的优于 Options API,推出 Vue 3 又到底是不是个正确的决定已经很难说个对错了。总之某一天 Vue 3 确实推出了,站在维护者的角度来说这很容易理解——大多数爱好造轮子的程序员看到多年前的屎山代码总是想做一次彻底的推倒重构的,而甚至还兼容着 IE 并采用了许多老 JS 特性的 Vue 2 在可维护性上显然已经遇到了不小的困难,其设计时未考虑到 TS 也使后续要做不少可能难度不大但工作量很大的类型体操来为 Options API 提供类型支持。既然都要推倒重来了,为什么不引入点新的东西?React Hooks 那一套东西不一定说真比 Options API 好,但对 TS 肯定是更友好的,并且看起来没比 Options API 有明显弱点,也能更灵活地组织代码——Composition API 就这么诞生了。
自 Vue 3 以来,Composition API 至少一定程度上带来了社区的繁荣——相比起 Mixin,Hooks 具有更简洁灵活的语法,并且在更容易避免冲突覆盖问题,这至少提高了库开发者的体验。而 vue-use 这样的项目要是没有 Composition API 也很难出现——Vue 2 中在功能上的扩展更多依赖于 Global methods,这种在全局对象上绑定太多东西的做法显然不够理想。在 Vue 2 生态中显然是很难出现一个质量和规模类似于 vue-use 的代码库的。
有一个流行许久的观点,即 Composition API 更适合大型项目,而 Options API 在中小型项目上可能有一定优势(Vue 3 的文档里也这么说,当然他们到底是不是真这么觉得就不得而知了)。这其实是个比较值得怀疑的论点,毕竟 Composition API 其实也很适合小项目,而 Vue 2 时期使用 Options API 构建的大项目也比比皆是。
Composition API 在提高了灵活性的同时没有很好保证代码质量的下限,因此引起了一些诟病,但对于习惯良好的程序员来说即使在小项目上可能也比起 Options API 编写更直观和易读的代码——在 Composition API 里可以随手拆个 Hook 出来,在 Options API 里难道会有人习惯于随手拆个 Mixin 吗?
可从另一个角度来说,Composition API 带来的能够更好按业务逻辑来组织代码的灵活性真的那么必要吗?如果组件粒度拆得够细,Options API 按功能分组的思路似乎也不坏,而 Composition API 提供的灵活性反而让人有些无所适从。而 Composition API 能随手拆个 Hook 出来的能力似乎也不那么有吸引力,我相信有许多人在真正写业务时是不经常拆 Hook 出来的,但只要代码规整地分块摆在一起也并不影响可维护性——在这种情况下,少数几个 Mixin 是否也已经够用?Mixin 得继承树要在多复杂的应用中才会看到可维护性的显著下降?
以前看过 Ruby on Rails 的纪录片,其中有个观点让我印象深刻——当一个技术流行起来后,人们总是开始讨论它能不能 Scale,又能 Scale 到何种程度,但大多数人一辈子也碰不到这项技术 Scale 的瓶颈,并且在真遇到 Scale 问题之前采用这项技术的小公司就已经 IPO 了。这里也同样如此,无论说是“Vue 相比于 React 更不适合大项目”还是说“Options API 相比于 Composition API 更不适合大项目”,都近乎源于一种其实没太大根据的刻板印象。
其实 Options API 在“人体工学”上是提供了比较不错的“幸福度”的——在我的观点里一是减少导入,二是敲 this.
就可以获得当前组件内全部关联数据和方法补全。说真的,“能提供更多补全可能”的设计在人体工程学上其实很重要,至少我是宁愿敲更多字也希望获得更好的补全体验的——而且 Vue 3 中 ref
的 .value
相比起 this
还没让人少敲字,这其实是引起了不少人的诟病的。
——好吧,对 Options API 和 Composition API 的偏题讨论就到此为止,再讨论下去大概也是得不出什么结果的。不过至少从现状来看,大家对 Vue 3 的接受度还不错,生态也在渐渐繁荣。在我的角度来看,这要很大程度归功于 Nuxt——Nuxt 目前对于复杂应用在成熟度上比起 Next.js 还有不少问题,但对于相对静态的公司/项目主页、发布页等应该算是我用过的元框架里 DX 最好的选择了。其实目前有不少大网站都是由 Nuxt 构建的,大家有兴趣可以浏览器装个 Vue Devtools 看下。
然后谈谈组件库的问题。国内和国外的组件库设计思路其实是很不一样的,国内的组件库通常是大而全,将你用得上的用不上的各种功能都封装进去,用起来就会比较省事,会发觉似乎什么场景都能直接用组件库提供的功能应付得来;国外的组件库相对来说更鼓励你造轮子,倾向于只封装基本组件并保留它们的灵活性,以便你自己进一步将它们更好地组成新的组件。其实我觉得国内的这个思路是要优于国外这些组件库的,只是由于审美不同,欧美更倾向于选用符合 Material 风格的缺胳膊少腿组件库,可能压根就没体验过使用国内这些大而全组件库开发的快乐感……例如国内组件库内置 Searchable MultiSelect 可以说就是标配,但诡异的是欧美常用的组件库里内置这东西的据我观察还还真不多。
如今看来,React 和 Vue 其实都有不少还不错的组件库选择,倒也很难说 Vue 这边的组件库生态不行了。如果倾向于大而全,React 选 AntD,Vue 选 Element Plus 应该没什么异议。其他的或许我可以举几个符合我个人审美和用起来不错的组件库说说,React 这边一个是 MUI,这组件库说实话设计得不咋好用但在欧美基本上有着和国内 AntD 类似的流行度,另外一些是 Chakra、Mantine 和近期的 shadcn/ui. Vue 这边,我个人除开 Element Plus 会比较倾向于 Naive UI 或 PrimeVue,另外 Material Design 的 Vue 组件库也有不少,但我不太喜欢这个设计所以就不提了。原题目描述中 Vue 组件库选择太少的问题大概已经不太明显了,并且现在基于 Tailwind CSS 的各种定制方案也挺流行的,手搓组件也没那么麻烦了,现在还有了 shadcn/ui 在各种框架上的版本,复制粘贴组件代码也并不麻烦。
回归问题本身吧。假如现在叫我做一个新项目,我大概还是会出于惯性选择 React——Vue 并没有什么不好,但我在 React 上着实有一些历史代码积累,对这边的生态也相对熟悉一些,并且用 React 整花活和对 TS 的兼容性上都要比 Vue 略微好上一些。但假如是做团队项目,出于对团队中其他人技术栈熟悉程度的考虑,我大概还是更倾向于 Vue——如果合作者都只会 Vue,我也不好叫人来现学 React.
说起来,其实选择 React 很多时候成了一种“潜意识”的做法——当你不管看到什么新轮子都拿如何在一个 React 应用中使用它作为示例,其实自然而然会遵照这种惯例,在没有特别理由的情况下默认选择 React——但仔细想想,又好像确实没有一定要选 React 的理由。并且尽管 React 在许多方面受到批评,但它本身没有比起其他 UI 框架有什么根本性的劣势,自然也没什么换掉它的理由——就像开头就反复提及的,这种庞大的生态和历史惯性大概已经决定了 React 在今日以及未来难以撼动的地位了,无论你对此是否抱有反感。很大程度上,这也是我习惯于使用 React 的理由。
至于其他 UI 框架,说真的 Svelte 和 Solid 那些还很不成熟,能用的组件库很少,基本上只有 Flowbite 这种基于 Tailwind CSS 的“跨框架”组件库兜底,在细致程度和易用性上都很难与专门为某一框架开发的组件库相提并论。除非只是做做那种偏海报展示的项目或者你真有足够耐心去手搓组件库,否则我是不建议在真是项目中上这些新兴框架的。嗯,还有被遗忘的 Angular——这我是真不熟,没法评价。
说来说去,最后还是写成了没啥参考价值的随感吐槽,那就到此为止吧。
","description":"很老的问题了,2024 年我站在自己的角度谈谈看法吧。(废话警告) 不算很久之前(大概是 2020-2021 年),当我初次在大学中接触前端领域时,周围的人都说想进大厂就学 React,并且互联网上也到处都是解析 React 函数式思想的文章——当时 React Hooks 推出才一两年,仍有大量项目基于 class component,而 Hooks 带来的更“纯粹”的“函数式编程”思想,在当时显得颇为独特与深奥。\\n\\n显然,这只是前端娱乐圈现状的又一个缩影,在那会儿是“Everyone’s talking about React Hooks and…","guid":"https://www.zhihu.com/question/294210442/answer/3453828000","author":"Snowflyt","authorUrl":null,"authorAvatar":null,"publishedAt":"2025-02-24T07:51:11.530Z","media":null,"categories":null,"attachments":null,"extra":null,"language":null},{"title":"尤雨溪发布了想法: VueConf 2024,这次是真回来了