造轮子的目的,是为了更爽的开发。当然,大家都在说,不要重复造轮子,只是我没有找到同样的轮子,才自己造了一个。也看到有人封装过 Element 的 Table,只是感觉封装的太浅,不够深入。下面说的这个,可能也是你需要的。
全文共 2388 字,读完需 6 分钟。
同步发表于知乎专栏:前端微志
惯例,开始之前,贴个Github地址,求 star😂。点击
阅读原文
去 GitHub 瞅瞅。
https://github.com/zollero/el-search-table-pagination
用 Vue 做前端开发的同学,肯定都听说过 Element UI (下文中称为 Element)这个由 饿了么前端团队 开发的基于 Vue 的 UI 组件库。
而用 Element 做的最多的就是 Table,且这个 Table 需要支持分页 和 搜索查询,且还会有一些操作按钮,用来处理数据。
前奏
系统中有很多页面都用到了 Element 的 Form, Table, Pagination 组件。当这种页面多了之后,就会出现很多重复代码,使得业务代码的占比不高,需要花更多的时候去维护非业务代码,效率不高,也有一些风险。
写多了之后,我决定封装一个通用组件,可以让我只用关注业务代码就可以。
一般情况下,我们使用 Element 的 Table,Pagination 组件 写一个简单的页面,会像下面这样。
(查看大图更清晰)
可以看出,要写这样一个页面,有一些东西需要处理,如:默认加载数据,分页切换等操作,都是需要单独处理。一般,在 Table 上面,还有一个搜索框,里面有几个搜索条件的输入框用来辅助搜索展示数据。这些操作步骤,是重复性的,再新建一个页面,都要再写一遍。
这样一个没效率的事情,怎么能忍?所以 el-search-table-pagination 应运而生,帮助开发者更好地用 Element 编写包含 Form,Table 和 Pagination 组件的页面。
还拿上图中的功能为例,用 el-search-table-pagination 重写之后,是下面这样的。
(查看大图更清晰)
重构之后,代码简洁很多,将通用代码抽离,开发者只需要关注业务代码即可,不用再维护很多重复代码。
特性
上面例子中说了 el-search-table-pagination 组件的简单使用,为了让它保持一定的通用性,做了一些封装,有一些细节你可能需要知道。
-
默认使用 axios 查询远程数据,当然你也可以配置一个封装之后的 axios(你可能会设置一些 interceptor)
-
最大化地像可配置化迈进,让你尽可能少的写 html,最大化地支持 Element 中的特性(持续更新)
-
同样可以配置搜索框中的搜索条件,如:输入框,下拉框,日期选择框、日期范围选择框等(后续会支持更多form item)
-
除了支持远程数据的分页查询展示,还支持本地数据的分页及查询过滤
-
CSS 样式使用 Element 中的样式,如果需要修改默认样式,按原来的方式做就行
-
table-column 中如果需要转换结构,可以使用 slot 来嵌套
使用
使用方法跟 Element 类似。
如果你想直接用,没有自己封装 axios,可以这样:
import Vue from 'vue'import ElSearchTablePagination from 'el-search-table-pagination'
// Default use axios as HTTP tool
Vue.use(ElSearchTablePagination)
如果你有自己封装 axios,可以在使用的时候,默认传入,这样将使用你传入的 axios 实例调用远程接口:
import Vue from 'vue'import ElSearchTablePagination from 'el-search-table-pagination'
// 你自己封装了 axios
import axios from './utils/axios'
Vue.use(ElSearchTablePagination, {
axios
})
当然,你也可以使用 CDN,在 html 文件中使用 script 标签来引用。
在 CODEPEN 上建了两个 DEMO 分别展示 本地数据 和 远程数据。DEMO 地址如下:
本地数据:
https://codepen.io/zollero/pen/wPRqYX
远程数据:
https://codepen.io/zollero/pen/xPmXBp
中文文档在此,欢迎打醒:
https://github.com/zollero/el-search-table-pagination/blob/HEAD/docs/zh_CN.md
注意事项
转换 table-column 内容的方式
很多时候,接口中字段的值,需要做转换才能展示,在 columns 中 column 的属性,提供了几种方式来帮你转换。
一、filter
如果你只需要使用 filter 转换这个字段的值,把 filter 的名称赋给filter就可以了,注意:只有注册在Vue 全局的 filter才有效
// 使用 filter 属性转换内容const columns = [
{
prop: 'updateTime',
label: '更新时间',
width: 110,
filter: 'formatDate'
},
...
]
上面用到的 filter 需要注册在 Vue 全局内才有效。
// 需要提前注册好这个 filterVue.filter('formatDate', (value) => {
if (!value) return '';
let d = new Date(value);
return d.getFullYear() + '-'
+ (d.getMonth() + 1) + '-'
+ d.getDate()
})
二、render
如果你想通过一个函数来转换一下,就把函数设置给 render 属性吧,记得将最终的值 return 出来。
// 使用 render 属性转换内容const columns = [
{
prop: 'price',
label: '价格
minWidth: 130,
render
: row => `${row.price} 元`
},
...
]
三、slotName
如果内容需要一段 HTML 重新填充到 table 内,这种方式最直观。首先在 el-search-table-pagination 标签内定义一个 slot,然后将 slot 的值赋给 slotName 即可。
// 使用 slotName 属性来转换内容const columns = [
{
label: '预览',
prop: 'url',
width: 380,
slotName: 'preview-column'
},
...
]
上面用到的 slot: preview-column 需要在 el-search-table-pagination 标签内声明,如下:
// 声明 slot,这种方式支持负责内容渲染// 代码中 slot-scope 属性是 Vue v2.5.x 之后的属性
// 如果你的 Vue 版本低于 v2.5.x,请使用 slot
:columns="columns"
... >
slot="preview-column"
slot-scope="scope">
width="350px"
:src="scope.row.url" />
操作列
很多场景下,都会需要在 Table 右侧添加一个 操作列,操作列里需要一些按钮,用来处理数据交互等。
这时候,你可以在 el-search-table-pagination 标签下使用 slot: append,可以在 Table 右侧添加一个 操作列。示例如下:
:columns="columns"
... >
slot
="append">
slot-scope="scope">
type="success">
通过
type="danger">
退回
Form 的配置化
插件提供了对 Form 表单的可配置实现,只需要提供 form-options 属性即可,其中 formOptions.forms 属性是一个数组,用来配置多个 form item。
forms 定义的 prop 属性的值,是会被传给后端接口的参数名。当然,传给后端接口的时候,还会带上分页参数。
首先需要注意的是属性:form.itemType
itemType
表示 from item 的类型,目前支持四种:input,select,date 和 daterange,且默认是 input。对应的是 Element 中的输入框,下拉框,日期选择框,日期范围选择框。
一、input
输入框比较简单,只需要设置好一下几个字段即可:
const forms = [ {
prop: 'url',
label: 'url地址',
size: 'small',
itemType: 'input'
},
...
]
二、select
下拉框相对复杂点,除了要配置 input 的那些参数,还有一些参数需要注意。
由于,下拉框的下拉选项的值可能是代码里写死的,也可能是从接口中获取的。所以,针对这两种提供了两种写法。
// 下拉选项的值是代码里写死的const forms = [
{
prop: 'status',
label: '状态',
size: 'small',
itemType: 'select',
options: [{
value: '',
label: '全部'
}, {
value: '1',
label: '通过'
}, {
value: '2',
label: '退回'
}]
},
...
]
// 下拉选项的值有部分是代码写死的