读读antd源码之导航组件

1,307 阅读4分钟

① 高内聚低耦合

如何抽离为一个组件,也是一个很重要的问题

无论是基础组件,还是业务组件,很多时候,对于很多的开发者,其实都没有十分清晰的边界。

甚至开发着,开发着,不同组件之间又会形成互相依赖了。

antd的源码本身,很多功能也是单独抽出来了一个仓库:github.com/orgs/react-…,这个库会提供更基础功能的封装,后面阅读的各项组件,会越来越多依赖这个库。

这篇文章将会对antd的导航部分的组件进行源码阅读:

② Affix(固钉)

将页面元素钉在可视范围

这个组件,其实就是为了实现 css 中的 sticky,如果不是为了兼容 IE,确实是可以不用它的:

所以实现这个组件有两个关键:一是确定滚动容器,二是监听滚动然后设置固定。

直接看一下源码(affix/index.tsx)的返回html结构先:

这里的最外层 ResizeObserver 就是来源于那个另外封装的仓库的 rc-resize-observer,源码地址在:github.com/react-compo…

主要为了监听 resize 事件,然后进行 updatePosition ,这里主要看计算位置的 measure 方法。

关键代码主要是获取容器的具体大小和位置信息,然后通过计算,进行相应的 fixed 定位:

但是它这里的代码有个很明显的问题,滚动是监听容器然后更新位置的,但是其实我们页面很多时候外部也是有滚动的,所以这个时候它不知道去更新位置的话,就会出现bug了。

它的 FAQ 也是有提到这个问题,这种情况需要另外手动去更新位置。

③ Breadcrumb(面包屑)

显示当前页面在系统层级结构中的位置,并能向上返回

这个组件比较简单,它内部主要多考虑了配合 routes 的渲染:

④ Dropdown(下拉菜单)

向下弹出的列表

这个组件最外包引用了 rc-dropdown 包了一层,源码在:github.com/react-compo…

所以还是要先看下它内部做了什么封装,发觉还是包了一层 rc-trigger,同在一个大仓库:GitHub - react-component/trigger: Abstract React Trigger

大致猜测一下,也能知道 Trigger 封装了主要的下拉弹出逻辑,位置和样式等内容。

再进去看看,可以看到监听了一堆trigger事件:onMouseEnter、onMouseMove、onMouseLeave、onPopupMouseEnter、onPopupMouseLeave、onFocus、onMouseDown、onTouchStart、onBlur、onContextMenu、onContextMenuClose、onClick、onPopupMouseDown、onDocumentClick

然后再看下生成下拉容器的逻辑,简单来说就是创建绝对定位的容器:

当然,还要考虑很多操作控制 popup 显隐的逻辑,代码还是相对规整,这里就不细节展开。

还有就是需要关注一下,关于显隐的过渡动画,这里它也封装了一个 rc-motion:GitHub - react-component/motion: ⛷ CSS Animation for React

如果有需要用到这种过渡的话,还是比较方便的,不用自己手写 Animation 和 Transition。

总体来说,这个 trigger 还是比较关键,信息展示类的地方用到比较多。

⑤ Menu(导航菜单)

为页面和功能提供导航的菜单列

这个组件也是封装了一个 rc-menu:GitHub - react-component/menu: React Menu

这里可以看下它如何处理 children 的,会根据子字节的各种类型来处理:

另外,菜单里它还用了一个 rc-overflow,用于处理容器内超出部分的处理,详细源码可以看:github.com/react-compo…

而一些展示的动效部分,也是用到前面提到的 rc-motion,其他一些逻辑都是比较常规的内容。

⑥ PageHeader(页头)

页头位于页容器中,页容器顶部,起到了内容概览和引导页级操作的作用。包括由面包屑、标题、页面内容简介、页面级操作等、页面级导航组成

这个页头的组件说实话比较适合无设计的项目,帮你组装了一些 title 或者 button 等的内容。

因为有设计的项目一般都会自己项目有一套自己的规范,不会按照它的布局或交互,所以参考意义不大。

⑦ Pagination(分页)

采用分页的形式分隔长列表,每次只加载一个页面

这里它也是封装了一个 rc-pagination, 发觉没有太多特别地方,和我们普通封装一个组件差不多,关键就是计算一下页码页数等内容,相对简单,而它切换一页显示多少条的 Select , 默认也是外部 selectComponentClass 传进去的,后面看到源码再展开一下。

⑧ Steps(步骤条)

引导用户按照流程完成任务的导航条

同样的,它这里也是用了封装的 rc-steps:github.com/react-compo…

这个组件相对简单,最适合我们来看它那种嵌套的应用方式:

我们平时写的组件,比较少像它这种使用方式:

需要依赖内外两个组件来达到想要的效果,所以可以直接看下它源码的处理:

其实也是相对简单,通过劫持了 children 之后,然后通过 cloneElement 传出新的合成的 childProps,使得内部的Step不用关心自身信息之外的 stepNumber 等。