作者:lin1997 原文链接:https://juejin.im/post/6888125003024629768
一个项目下来发现有很多看似相似但又有区别的功能,想想如果一个一个的去写这种相似又有区别的功能,就会显的乏味枯燥,而且更关键的是这样的代码使得项目更难的去维护。如何让项目焕然一新,并且方便以后需求迭代的时候更好的维护呢?那就动手封装组件吧,让那些相似的功能需求都统一管理统一配置。
当我拿到需求的时候,我先看了element-ui
的组件是否满足我业务上的需求(ps:如果在 elemnt-ui 组件的基础上去做改造也是 ok 的),但后来我发现 element-ui 的表格组件无法满足我这次的业务需求,通过改造element-ui
当中的组件也超级麻烦。最后,我还是决定自己封装一个多功能的 table 组件吧.......功能需求如下:1.表格数据的树形渲染并且同个父级下的同层级可拖拽,不同层级无法完成拖拽。2.表格行可操作(ps:比如编辑,删除,查看详情)3.表格的顶部可操作(ps:展开,排序)4.表格尾部可分页 5.表格可多选(ps:表格带复选框)
npm install element-ui sortablejs -S
在项目中我是使用sortablejs
实现拖拽的,以及使用elemnt-ui
的分页组件实现分页的功能。
因为是树形结构的数据,所以我想到了递归组件。在设计递归组件之前先了解树形结构的数据是长什么样的。
如下图通过给组件命名 recursiveRow,并且在该组件的模板里使用该组件。好吧,到这里即完成了递归组件的第一步...
我将每一行设计成一个组件,如果该行数据有 children 那么就在渲染一次 recursiveRow 组件。好吧,到这里实现了递归的条件了。接下来就是完成每一行数据的代码编写了。具体如何完成每一行数据的代码编写我等后续再补充,接下来我们先来了接这个组件的配置表。
这个组件通过表头的配置实现了组件的统一管理,表头配置项的设计主要是通过一个JSON
来实现的。JSON
是通过字段name
、props
、before
、images
、actions
、attr
、select
、tree
、name
、props
表格的基础配置是通过字段name
和props
来设计的。
这样的基础配置渲染出来页面如下:
一般一个表格组件不仅仅只有渲染的功能就完事了,还会有其他的操作,比如删除,编辑,比如复选框,以及属性数据的样式配置等等...行操作的表头配置我是通过actions
配置进行的,可以传递点击的事件,并且执行该事件可以获取每行的数据,以及改行的索引,还有事件对象。其属性是通过attr
来配置的。
如果需要复选框可通过配置select
,将改字段设置为true
。通过配置attr
来配置属性,当然如果不传也可以,有默认值。那如何获取到每行勾选所对应的值呢?留个疑问,后续我们再讲述。
如果确定了哪个字段是需要渲染成树形的图案,可以通过配置tree
,将改字段设置为true
就可以,可以通过配置before
可以特殊渲染每一个格子的数据。
当完成表头配置项的设计之后,如何传递属性,如何设计上面讲到的每行编码就是接下来要考虑的。这里的核心是通过 v-bind,当 v-bind 不带参数的是将会把整个对象的所有属性都绑定到当前元素上。以及v-on将事件一一绑定到元素上。组件中使用了 \attrs[1]对象属性的集合和\listeners[2]对象事件的集合来实现属性的跨阶级传递,监听事件的传递。将绑定在 table 组件的属性和事件通过跨阶级传递给递归组件,使得递归组件接收属性和事件。自定义递归组件:
有了表头和表格数据就可以实现每行的编码了,就是遍历 table 数据和表头数据.,来完成每行的编码,并将其属性进行绑定。在实现每行的过程中,使用了 vue 提供的一个动态组件component
来实现动态的标签渲染。
select-change
事件,该事件会返回每次所勾选的值。其实现的思想就是保存每次勾选的值,过滤每次反选的值,具体的想了解实现过程可查看源码。slot
来实现的。所以可自定义顶部的操作以及尾部的分页。openAllTree
来实现的,可以通过绑定ref
再外部获取这个函数。openAllTree
其实现的思想是通过改变数据,让数据去驱动视图;在递归组件中封装一个函数用来将当前作用域的内部属性更新,在 table 组件中循环执行每一个递归组件的函数。具体的想了解实现过程可查看源码。isSort
来开启和关闭排序功能。给每一个递归组件绑定一个ref
属性,那么通过 new Sortable 实例实现同层级的拖拽(这里的同层级就是相同层级节点并且同个父节点的可互拖)。其实现的思想是通过绑定ref
属性可获取当前组件的数据流(ps:因为每一个组件都有自己的作用域,所以是独立的),那么通过数据再去驱动视图。在这里还要注意isSort
的数据更改以及拖拽完成之后的表格数据更新,所以在通过接收属性 callback 来实现表格数据的更新(ps:回调函数的思想)。内部是通过函数handlerSort
实现的,具体的想了解可查看源码。handlerEdit
。其思路是通过增加改行的字段component
来配置修改HTML标签
,以及修改行的该字段的数据。具体的实现可查看源码。自定义组件 table
如下图:
样式可自行修改哈~~
组件源码地址可查看:源码地址[3]
很多人可能会觉得那么多组件库为什么要自己封装组件呢,有这个必要吗?其实在分析这个需求的时候,我也曾尝试去找资源,但发现基本上都是文件夹一样的拖拽功能...所以,我后来就决定自行封装。当然在开发的过程当中,我觉得封装组件是有必要的,既不会代码冗余显得臃肿而且还实现统一配置管理可以让项目更稳步的实现迭代。最后,对各大掘友有帮助的话希望赏个 star ~(ps:不要吝啬哦)
[1]
$attrs: https://cn.vuejs.org/v2/api/#vm-attrs
[2]
$listeners: https://cn.vuejs.org/v2/api/#vm-listeners
[3]
源码地址: https://github.com/hhl-web/vue-ts-components