6

或许这就是下一代组件库

 3 years ago
source link: https://zhuanlan.zhihu.com/p/252824872
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

或许这就是下一代组件库

自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 都在讨论开发中,如果你有兴趣,可以发送简历到 [email protected],加入我们,一起打造下一代组件库,当然。同时项目组也有"海量"实习生名额。

注意:默认投递公司是蚂蚁金服战略投资的公司 —— 校宝在线,如果你要投递的是蚂蚁金服体验技术部,在邮件中特别注明。

最后的最后,useXxxx 是一个新的仓库,点个 star 再走呗


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK