react组件库调研之Button篇

1,958 阅读5分钟

背景介绍

很荣幸,我们小组接到了内部react组件库zent的改版需求,为了写出更好的组件,更优秀的代码,对现有优秀组件库的调研,肯定是必不可少的。

虽然任务里说的是竞品调研,但以我们的使用体量,应该根本算不上竞品,毕竟连我在接到任务前根本没听说过zent,只知道vant。说到vant,有赞前端中台招人,来了就可以和被尤大大夸赞过的vant作者chenjiahan大哥,一起上山点菜,一起打王者,还能给你打辅助,直接留言或者联系我都行!

言归正传,首先感谢ant,给了我最初调研的素材。其次,感谢字节的大佬们,雪中送炭开源了semiarco

我分到的基本都是form组件的开发和修改,第一篇,就先从button开始了。

调研ing

大部分的篇幅肯定都是介绍大佬们开发的3个库的,毕竟要抱着学习的心态,绝对不是因为怕吐槽zent被发现,被大哥们按在地上打。

ui对比

个人见解:semi > ant > arco = ??

semi

image.png

ant

image.png

arco

image.png

??

image.png

功能对比

框架 \ 功能text按钮icon按钮链接按钮禁用加载组合按钮下拉按钮组
ant×
semi×
arco×
zent开发ing修改ing准备开发ing

在功能上,基本都是该有的都有,antarco基本是持平的,ant多了个dashed边框,loading支持传delay控制时间,而semi虽然少了链接按钮功能,但是文档里也写了,推荐用link属性来实现,而且多了一个下拉按钮组的功能,下面放图了,且semiicon支持通过iconPosition控制位置,而antarco需要手动写到button里。

image.png

代码风格对比

我可太喜欢semi的代码风格了,截图截不全,就隐藏了几个对象,截了个图,清晰易懂,虽然把iconButtonbutton分成了2个组件,但是这个代码确实我喜欢的写法和风格(清晰到连我都看得懂)。

image.png

而且,semiant的代码,在button中可以说是毫不相关,借鉴什么的根本不存在。不过有趣的事情还是出现了,只上图,不说话。

image.png

代码分析

首先,因为button算是一个比较基础简单的组件,大多数的功能其实都是依靠props配合cssclass来实现的。

image.png

截图里的是semi中的代码,根据传入props不同的值,来实现按钮不同的样式。按钮中能分析的点,其实就是icon中的逻辑和2个中文字之间自动加空格。

icon处理

icon的处理简单来说,就是确定icon的位置然后把children塞到icon的左边或者右边。

semi的做法是不处理children,直接在children外面整个套个span,然后根据iconPosition判断margin-left/right,在span上直接套style

antarco的处理就相对复杂一点,就是上面截图的雷同的那一段代码,拿arco的举例。

function processChildren(children?: ReactNode) {
  const childrenList = [];
  let isPrevChildPure = false;
  React.Children.forEach(children, (child) => {
    const isCurrentChildPure = typeof child === 'string' || typeof child === 'number';
    if (isCurrentChildPure && isPrevChildPure) {
      const lastIndex = childrenList.length - 1;
      const lastChild = childrenList[lastIndex];
      childrenList[lastIndex] = `${lastChild}${child}`;
    } else {
      childrenList.push(child);
    }
    isPrevChildPure = isCurrentChildPure;
  });
  return React.Children.map(childrenList, (child) =>
    typeof child === 'string' ? <span>{child}</span> : child
  );
}

其实就是把stringnumber类型的child整合到了一起,放进了一个span里,然后再从css入手,给svgspan中加个margin

image.png

如果不是string的内容,也就不会产生margin了,随便整个a标签,因为逻辑没走到加span这步,也就不会有margin了。

image.png

2个汉字间自动加空格

这个功能描述起来不是很通俗易懂,上个图就明白了。semi没有提供这个功能,arcoantconfigProvider配一下,就能使用了,ant是默认开的。描述一下,就是如果按钮的child是两个汉字的话,就自动在中间加个空格,美观一点。

image.png

判断是否是2个中文,只需要正则判断一下就行了。

const rxTwoCNChar = /^[\u4e00-\u9fa5]{2}$/;
const isTwoCNChar = rxTwoCNChar.test.bind(rxTwoCNChar);

虽然是一个功能,但是antsemi实现的方案也不一样。

ant中,当只有一个child时,spaceChildren之后,ant会把string形式的child,手动添加一个空格。

if (typeof child === 'string') {
  return isTwoCNChar(child) ? <span>{child.split('').join(SPACE)}</span> : <span>{child}</span>;
}

但在arco中,则是采用了css中的letter-spacing的方式来完成这个样式。

image.png

image.png

综合评判一下,我感觉这波应该是arco赢了,在ant中,如果我添加2个都是一个汉字的child后,并不会自动添加空格,因为在React.Children.count(children) === 1这个逻辑下就挂了,而arco因为直接是css控制,不会受到影响。

const a = '确';
const b = '定';
<Button type="primary">{a}{b}</Button>

image.png

当然可能也是我没有考虑到另外一些点,如果说错了,也希望大佬可以纠正。

动画

动画这个只有ant做了,在点击ant的按钮时,会发现周围会有波浪形状的阴影波动,这个截图太难了,大家可以自己点一点,因为antbutton外面又套了一层的wave的动画组件。大佬果然牛逼,简简单单地按钮也安排得明明白白。

image.png

感兴趣的大哥,可以去看一看,动画的事情,无非就是点一点加个class,然后写个animation罢了。

虽然我不会,但是我会吹牛。

总结

其实最先看的不是button的,而是input的,但是因为button的组件相对来说比较简单,可以边写边练手,input有些过于复杂了,直接来写应该是一坨屎。

虽然button组件相对简单,但是也从大佬们的代码中学到了很多,受益匪浅。

button篇写的还算顺畅,下一篇input边写边改边学,也不知道要多久才能熬出来~