背景
ElementUI 是一个优秀的组件库,但其 Table
组件的使用方式总让我感觉有些麻烦,我们看下官方文档的示例:
<el-table
:data="tableData"
style="width: 100%">
<el-table-column
prop="date"
label="日期"
width="180">
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="180">
</el-table-column>
<el-table-column
prop="address"
label="地址">
</el-table-column>
</el-table>
复制代码
开发者需要在el-table
组件中用 el-table-column
注册想要展示的列,试想一下如果表格有很多列,则需要在 template
中书写大量的 el-table-column
, 这无疑会增加后续的维护成本。而社区中其他组件库的表格,通过一个 columns
数组就可以渲染出想要的列,我们看下 iView 的官方示例:
<template>
<Table :columns="columns" :data="data"></Table>
</template>
<script>
export default {
data () {
return {
columns: [
{
title: 'Name',
key: 'name'
},
{
title: 'Age',
key: 'age'
},
{
title: 'Address',
key: 'address'
}
],
// ...
}
}
}
</script>
复制代码
此外,因为我们的管理后台项目中存在大量的列表型页面,此类页面的结构大都相同,所有我想在 Table
的基础上更进一步,于是 TableView
组件应运而生。
TableView
TableView
是一个以 Table 为主要内容的页面容器,例如管理后台项目里的各种列表。这类页面一般都包含 搜索、表格、页脚、工具栏 和 表格自定义 几个部分,页面特征明显,可复用性高。TableView
允许你传入一个 columns
数组即可渲染表格中所有的列,每一列还支持通过 render
函数或插槽自定义。此外,它还内置了分页逻辑,并允许用户自定义展示哪些列,但搜索表单部分还需要使用者自己完成,并通过插槽嵌入 TableView
。
TableView
结构如下图:
internals 为组件内置的功能,包括 Table
部分的列表渲染,footer
部分的分页,还有 customer
部分的列表自定义(自定义展示哪些列)。
slots 插槽当前包含:
-
filter
页面筛选器,嵌入搜索表单
-
tabBar
有些页面顶部需要 tab 切换,例如订单管理模块下的待审列表,其又细分为 “待初审”,“初审退回” 等状态。
-
toolBar
工具栏部分,可在此出嵌入一些按钮,如:导出,新增。
使用
基本用法
图中红色部分即为 TableView
, 使用者传入一个 columns 数组即可渲染出表格,代码如下:
<template>
<table-view
:columns="columns"
get-list-method="getDataList"
>
<template #filter="{ search }">
<order-filter
@search="search($event)"
@reset="search($event)"
/>
</template>
<template #toolBar>
<el-button
type="primary"
size="small"
>导出</el-button>
</template>
</table-view>
</template>
<script>
export default {
// ...
data() {
return {
columns: [
{
label: 'Name',
prop: 'name',
},
{
label: 'Age',
prop: 'age'
},
{
label: 'Address',
prop: 'address'
}
]
};
},
methods: {
async getDataList(params) {
const res = await Api.getList(params)
return {
listData: res.list,
total: res.total,
page: res.page
}
}
}
};
</script>
复制代码
描述每一列的对象(column
对象)的完整属性如下, 你可以灵活的控制每一列的展示
{
// required
label: '姓名',
// required
prop: 'name',
// ElTableColumn 的属性
elProps: {
fixed: true,
},
// 是否展示
// 组件prop `useColumnCustomer` 为 true 时生效
// show 为 false 的列隐藏
show: true,
// 可通过 render 函数自定义每列展示的内容
// row: 行数据
// col: 列数据
// rowIdx: 行索引 (从0开始)
// colIdx: 列索引 (从0开始)
render(h, { row, col, rowIdx, colIdx }) {
return h(
'div',
{ /* ... */ },
`${row.name}`
)
}
}
复制代码
如何自定义列?
TableView
支持通过 render
函数 和 插槽 两种方式自定义列
注意:render 优先级高于插槽
1. render函数
给需要自定义的列设置一个 render 函数, 你可以通过 render 函数渲染想要的内容。如果你自定义的内容比较复杂,你可以像操作列那样,封装一个组件传给渲染函数。
import OperationWidget from './OperationWidget.vue'
export default {
// ...
data() {
return {
columns: [
{
label: '姓名',
name: 'prop',
render(h, { row, col, rowIdx, colIdx }) {
return h(
'div',
{ /* ... */ },
`${row.name}`
)
}
},
{
label: '操作',
prop: 'operation',
render(h, { row }) {
return h(OperationWidget, {
props: {
orderInfo: row
}
})
}
}
];
}
}
}
复制代码
2. 插槽
TableView
允许你通过具名插槽自定义列,插槽名为列的 prop
<template>
<table-view
:columns="columns"
:get-list-method="getListMethod">
<!-- 'name' 插槽会自定义 prop 为 'name' 的列 -->
<template #name="{ row }">
<!-- slot what you want -->
<div>{{ row.name }}</div>
</template>
</table-view>
</template>
复制代码
如何请求数据?
TableView
要求使用者在 getListMethod
里调用接口并回填数据, getListMethod有两种写法:
- 异步写法
第一种是写一个返回 Promise
的函数, Promise 需 resolve 接口返回的数据,就像这样:
async getDataList(params) {
const res = await Api.getList(params)
return {
listData: res.list, // 表格数据
total: res.total, // 总数
page: res.page // 当前页数
}
}
复制代码
- 回调写法
TableView
内部在调用 getListMethod
的时候会传两个参数,第一个是请求参数,第二个则是一个回调函数,用于设置数据, 所以 getListMethod
也可使用如下写法:
getDataList(params, callback) {
Api
.getList(params)
.then(res => {
callback({
listData: res.list, // 表格数据
total: res.total, // 总数
page: res.page // 当前页数
})
)
}
复制代码
如何搜索?
TableView
需要使用者自己整理搜索条件,然后手动调用内部方法 search
,如图:
有两种方式调用 search
:
1. 通过作用域插槽
<table-view
:columns="columns"
get-list-method="getDataList"
>
<template #filter="{ search }">
<order-filter
@search="search($event)"
@reset="search($event)"
/>
</template>
</table-view>
复制代码
2. 通过 ref
<template>
<table-view
ref="tableView"
:columns="columns"
get-list-method="getDataList"
>
<template #filter>
<order-filter
@search="search($event)"
@reset="search($event)"
/>
</template>
</table-view>
</template>
<script>
export default {
// ...
methods: {
search(params) {
this.$refs.tableView.search(params)
}
}
}
</script>
复制代码
使用内置的自定义列表功能
TableView
内置了自定义列的组件,支持用户勾选想展示的列,隐藏多余的列。
想要使用此功能,需要设置 useColumnCustomer
为 true
, 同时给组件传递 columnCustomMethod
方法。你需要通过 columnCustomMethod
更新 columns
, 把自定义展示的列的 show
设为 true
, 其他列的 show
设为 false
。
<table-view
:columns="columns"
use-column-customer
:column-custom-method="columnCustomMethod"
get-list-method="getDataList"
>
<!-- ... -->
</table-view>
复制代码
export default {
// ...
methods: {
/**
* 处理列表自定义
*/
columnCustomMethod(columnProps) {
this.columns = this.columns.map(col => ({
...col,
show: columnProps.includes(col.prop)
}))
// ...
}
}
}
复制代码
当然你还可以更进一步,在 columnCustomMethod
里保存用户自定义的数据,下次渲染列表的时候根据保存的数据把 columns
对应的列的 show
设为 true
。
源码
对 TableView
的介绍到此为止,如果你感兴趣的话,请前往 GitHub 查看源码和完整文档。求建议求 star 🌟。 此外,我把 Table
封装为独立的组件,如果你只想使用 Table
部分,请直接查看 src/Table.vue
文件