查看原文
其他

【第2072期】 或许这就是下一代组件库

唐金州 前端早读课 2021-03-03

前言

来了解下下一代组件库。今日早读文章由@唐金州投稿分享。

正文从这开始~~

自react、vue等数据驱动的框架流行以来,诞生了许多相关组件库,但这些组件库的编程模式基本都是大同小异,虽然这些年都在不断迭代,但除了功能更加丰满,长相更加好看之外,也基本上没有什么质的变化。在 material、antd 等垄断地位下,也很少有个人或公司去选择做组件库了,组件库也逐渐退出了各大会议论坛。但随着 react hooks、vue composition api 的推出,我想,或许组件库有了新的突破点。

从某种意义上来说,组件可以分为有状态组件和无状态组件(函数式组件),理想状态下,我们期望所有的组件都是无状态组件,但实际上,组件库提供的组件 90% 以上都是有状态组件,因为组件内部不得不要维护一套逻辑非常复杂的状态,这不仅让代码的易读性、可维护性降低,也增加了个性定制化组件的难度。antd 为了让用户能够自己定制化组件,底层提供了 rc-xxx 一系列更加原子化的组件,但依然会受限于 html 结构,导致一些场景无法满足。

如果说,我们能够将“状态“和 UI 彻底(理想状态)分开,组件都是无状态组件,只接收属性,负责展示,所有的状态逻辑交由一个独立的包(这里我们暂且叫他 use-hooks吧)去管理,会发生什么?

  • 我不喜欢 ant design 的设计,你可以只使用 use-hooks,去写一套自己的无状态组件库

  • 我害怕圣诞彩蛋,你可以只使用无状态组件库,去写一套自己的 use-hooks

  • react、vue 版本合并在一个包里不再是梦

  • ant design 将不仅是设计语言,还是组件库基础设施

当然,以上或许都是理想状态,但我们一直在往这个方向上努力。而且有了一定的成果,下面通过 Vue 的示例来进一步的体验。

Vue 3 最大的特性是 composition api,它提供了一种方式让我们可以更大限度的复用逻辑,也让我们在开发大型项目的时候,使得逻辑更加清晰,在我们开发 Ant Design Vue 2.0 的时候发现,除了逻辑复用,composition api 还能帮助我们做组件解耦。

在我们开发组件的时候一直尽可能的做到“高内聚、低耦合”,但是有些组件始终没能彻底解耦,尤其是 Form 表单组件,没错,流水的组件,铁打的 Form:

历史不再提,直接看现状:

我几乎查看了现有的基于 Vue 的所有主流组件库,包括 vuetify、element、vant 等,它们的 form 表单组件基本都是一个套路,当然也包括 ant-design-vue,都是在 form 中使用 provide 提供表单上下文,在 form-item 中使用 inject 注入表单上下文,input / select 等组件通过某种约定(或发布订阅、或依赖注入、或被动劫持)来和 form、form-item产生“通信“。这几个组件在源码层面就产生了各种耦合,对于使用层面,也不例外,各个组件之间必须按照“严格“的 API 规范进行传递参数,校验逻辑和展示强绑定。

还是举个🌰更直观,产品&设计要实现如下图示的一个表单,所有的错误信息统一在一处显示:

尼玛,组件库不支持,要自研,实现成本高,要延期,和历史设计规范不一致,改设计,总之各种借口和理由开始各方撕逼了。

为了解决这一问题,当然不是撕逼的问题,而是组件逻辑和展示耦合的问题,我们提出了表单校验中心化处理的方案 —— useForm,表单的校验状态完全在useForm中去处理,对于a-form、a-form-item,仅仅用来做表单布局和样式,不再做校验的逻辑,他们之间也不用通过各种方法进行通信。甚至可以不需要 a-form,你可以使用任何html标签替代,当然为了语义化,多写几个字符串也没啥毛病。

上代码:

定义一个响应式的数据和表单域规则:

  1. // 数据

  2. const modelRef = reactive({

  3. name: '',

  4. region: undefined,

  5. type: [],

  6. });

  7. // 表单域规则

  8. const rulesRef = reactive({

  9. name: [

  10. {

  11. required: true,

  12. message: 'Please input name',

  13. },

  14. ],

  15. region: [

  16. {

  17. required: true,

  18. message: 'Please select region',

  19. },

  20. ],

  21. type: [

  22. {

  23. required: true,

  24. message: 'Please select type',

  25. type: 'array',

  26. },

  27. ],

  28. });

分别作为 useForm 的第一和第二参数,返回值中将包含响应式的校验结果信息以及其它的辅助方法:

  1. const { resetFields, validate, validateInfos, mergeValidateInfo } = useForm(modelRef, rulesRef);

你可以将校验结果绑定到任意 a-form-item上,如:

  1. <a-form-item v-bind="validateInfos.name"></a-form-item>

你不需要关心 validateInfos.name 里面都有什么值,当然如果你想做更加自定义化的UI,例如,你想将错误信息通过弹窗的形式展示:

  1. if(validateInfos.name.validateStatus === 'error') {

  2. alert(validateInfos.name.message);

  3. }

而 mergeValidateInfo 只是我们根据常用业务场景提供了一个合并校验信息的辅助方法,就像我们上方截图所示的合并错误信息在表单底部统一展示,代码如下:

  1. const errorInfos = computed(() => {

  2. return mergeValidateInfo(...toArray(validateInfos));

  3. });

  1. <a-form-item class="error-infos" v-bind="errorInfos">

  2. <a-button type="primary" @click="onSubmit">

  3. Create

  4. </a-button>

  5. </a-form-item>

完整代码可以通过 ant design vue 官网查看。

useForm 的 API 或许繁琐了些,但我更想分享的是一种思想,而且 useForm 的api 现在还处在讨论阶段,如果你有好的建议可以通过 issue 和我们互动交流。

除了 useForm,众多 useXxxx 都在讨论开发中,如果你有兴趣,可以发送简历到 antdv@foxmail.com,加入我们,一起打造下一代组件库,当然。同时项目组也有"海量"实习生名额。

最后的最后,useXxxx 是一个新的仓库,点个 star 再走呗 https://github.com/vueComponent/use

关于本文 作者:@唐金州 原文:https://mp.weixin.qq.com/s/u2T2y4UgmfAAFUeTUpVJbQ

为你推荐


【第2032期】基于react的组件库主题设计方案


欢迎自荐投稿,前端早读课等你来

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存