掌握了开源框架还不够,你更需要掌握源代码 (2)

实现这个功能的问题不是非常大,按照官方的文档都能解决。其中主要利用了列组件中的 el-table-column 的 header 插槽(Slot),在其中加入弹出框(Popover)。很好,So far so good!接下来就是加入列的自定义功能了,看上去很快就要大功告成了嘛。

问题初显

要实现列的自定义,最完美的实现方法就是让用户点击操作按钮,弹出对话框(Dialog),里面可以选择要展现的列,用拖拽的方式将其排序,然后点击确认。然后我在 Element Plus 官网上快速找到了一个新组件,穿梭框(Transfer),效果如下图。理论上,只要我在对话框中引用该弹出框来控制展现列的数组就可以了,例如将要展示的列放到 “列表2” 中。锵锵!目前看起来似乎一切非常顺利。

掌握了开源框架还不够,你更需要掌握源代码

不过,在仔细阅读文档之后我发现该组件并不支持拖拽,因此暂时无法实现列排序的功能。虽然有点沮丧,但这个影响不大,我们主要想实现的是列选择功能。排序虽然也重要,但暂时先搁置一下,先实现组件选择再说!

然而,现实总是出乎意料。笔者在进一步试验中发现,这个组件似乎存在一个重大 Bug:当穿梭框中全选候选元素时,竟然无法选择或取消选择了(向左移动或向右移动)!赶紧仔细调试查找原因,反复确认是不是我自己写的代码有问题。然后发现是 Vue 在更新组件时在 runtime-core.esm-builder.js 中的 patchBlockChildren 方法下出现了 oldChildren 为 null 的情况。进一步阅读 Element Plus 中穿梭框组件的相关源代码之后,怀疑是 transfer-panel.vue 这个子组件出了问题,它更新渲染的时候 el-checkbox-group 不存在,因此导致更新时出错。随后我在 Element Plus 的 Github 仓库中提交了 Bug Issue。不过维护者并不认为我反映的问题是 Bug,因为在 CodePen 上似乎没有问题。但这个 Bug 确实在我的项目中客观存在,可以在 crawlab-frontend 的 历史提交 中复现。

再遇困境

无奈之下,自行琢磨半天无果之后,果断决定自己造轮子。很快从头写了一个类似穿梭框的组件出来,组件效果如下图。新写的组件在外观上与之前的非常类似,不过自由度很高,因此也顺便支持了拖拽功能。看上去问题似乎快要解决了。

掌握了开源框架还不够,你更需要掌握源代码

不过,当我满怀期望准备测试拖拽排序功能时,意想不到的事情发生了:列顺序数据改变之后,表格列竟然没有任何改变!改变列组件 el-table-column 的顺序对界面展示的竟然没有作用!而在官方文档的定义中,el-table-column 的顺序决定着列的实际展示顺序。经过重复多次试验之后,笔者只好承认原先的实现方式有问题。简单的改变模版中的列组件顺序并不会影响界面上的展示。

笔者当时想到一个 “聪(yu)明(chun)” 的办法。我试图用强制刷新表格组件的方式让其数据重新渲染,达到改变列顺序的目的。但经过测试,发现这样的暴力方式存在很大的性能问题,每次点击 “Apply” 之后会卡顿近一秒。

于是,笔者又陷入了绝望的境地。

抽丝剥茧

在进退两难的情况下,笔者停下来仔细思考。是不是我对 Element Plus 的框架还不够了解?表格组件本身是如何实现的?它有什么限制和缺点?这些问题都推动我进一步来拆解 Element Plus 框架本身,也就是去阅读它的源代码,理解组件本身的代码逻辑和工作原理。于是,笔者克隆了 Element Plus 代码仓库 到本地。

非常幸运,Element Plus 项目的代码质量相当高,代码组织结构和命名方式都非常清晰。虽然注释相对来说偏少,但它清晰的逻辑结构和良好的命名规范让可读性变得很强。在惊叹于大厂工程师职业素养的同时,我也快速定位到了表格组件的源码位置 packages/table。整个 Element Plus 项目是用 MonoRepo 的方式管理的,简单来说是一个 Git 仓库里有很多个 NPM 项目。管理工具使用了 Lerna。下面是 el-table 组件 NPM 项目的代码组织结构。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsfxdy.html