【第2072期】 或许这就是下一代组件库
前言
来了解下下一代组件库。今日早读文章由@唐金州投稿分享。
正文从这开始~~
自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标签替代,当然为了语义化,多写几个字符串也没啥毛病。
上代码:
定义一个响应式的数据和表单域规则:
// 数据
const modelRef = reactive({
name: '',
region: undefined,
type: [],
});
// 表单域规则
const rulesRef = reactive({
name: [
{
required: true,
message: 'Please input name',
},
],
region: [
{
required: true,
message: 'Please select region',
},
],
type: [
{
required: true,
message: 'Please select type',
type: 'array',
},
],
});
分别作为 useForm 的第一和第二参数,返回值中将包含响应式的校验结果信息以及其它的辅助方法:
const { resetFields, validate, validateInfos, mergeValidateInfo } = useForm(modelRef, rulesRef);
你可以将校验结果绑定到任意 a-form-item上,如:
<a-form-item v-bind="validateInfos.name"></a-form-item>
你不需要关心 validateInfos.name 里面都有什么值,当然如果你想做更加自定义化的UI,例如,你想将错误信息通过弹窗的形式展示:
if(validateInfos.name.validateStatus === 'error') {
alert(validateInfos.name.message);
}
而 mergeValidateInfo 只是我们根据常用业务场景提供了一个合并校验信息的辅助方法,就像我们上方截图所示的合并错误信息在表单底部统一展示,代码如下:
const errorInfos = computed(() => {
return mergeValidateInfo(...toArray(validateInfos));
});
<a-form-item class="error-infos" v-bind="errorInfos">
<a-button type="primary" @click="onSubmit">
Create
</a-button>
</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
为你推荐
欢迎自荐投稿,前端早读课等你来