vue+render实现el-table多表头

一、前言

又好久没更新文章了。。补一篇,主要分享封装多表头表格render函数实现多表头表格

在公司维护低代码平台,有个需求需要通过拖拽配置一个多表头的表格(element的el-table),但是发现网上好像没什么资料,特别是平台是通过render函数实现的,对这个还不是很熟悉,摸索着写出来了,分享一下

二、Render函数代码

首先说明一下,用render函数纯粹是为了拖拽组件以及配置字段后之后可以即时预览,真正开发还是使用公用的表格组件

这部分代码是公用的,多个组件都用这一个,我稍微改了改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import columns from './multi-table'
export default {
render(h) {
// 深拷贝一份出来
const confClone = deepClone(this.conf)
// 准备 h 函数的第三个参数, 也就是子节点
const children = columns(h, confClone)
const dataObject = {
attrs: {},
props: {},
nativeOn: {},
on: {},
style: {}
}
// 将json表单配置转化为vue render可以识别的"数据对象(dataObject)"
Object.keys(confClone).forEach(key => {
const val = confClone[key]
if (key === '__vModel__') {
// 双向绑定v-model
dataObject.props.value = confClone.__config__.defaultValue
dataObject.on.input = val => {
this.$emit('input', val)
}
} else if (dataObject[key]) {
dataObject[key] = {
...dataObject[key],
...val
}
} else {
dataObject.attrs[key] = val
}
})

return h('el-table', dataObject, children)
},
props: ['conf']
}

columns函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* 递归渲染子节点
* @param {Object} item
*/
function renderChildren(h, item) {
// 递归出口
if (!item.children || item.children.length == 0) {
return [h('el-table-column', {
props: {
label: item.label
}
})];
} else {
// 核心在这里,递归调用
let arr = item.children.map(item => renderChildren(h, item));
return h('el-table-column', {
props: {
label: item.label
}
}, arr);
}
}
export default {
columns(h, conf) {
const list = [];
// 针对每一个columns渲染一个el-table-columns
conf.__slot__.columns.forEach(item => {
list.push(renderChildren(h, item));
});
return list
}
}

三、附录

1. 公用表格组件

每个公司的业务不同,我只贴核心部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<el-table>
<!-- index列 -->
<el-table-column v-if="showIndex" type="index" width="50"></el-table-column>
<!-- selection列 -->
<el-table-column v-if="showSelection" type="selection" width="55"></el-table-column>
<!-- 解决列错乱问题,因为el-table不支持嵌套除了el-table-column的组件 -->
<el-table-column width="1"></el-table-column>
<!-- 渲染列, 支持多级表头 -->
<LRTableColumn v-for="(column, cindex) in filterColumns()" :key="cindex" :column="column"></LRTableColumn>
<!-- 自定义操作列 -->
<el-table-column v-if="customBtn.display" :min-width="100" label="操作" fixed="right">
<template slot-scope="scope">
<span v-for="(bColumn, bindex) in customBtn.btnColumns" :key="bindex">
<Button v-if="!scope.row.children" type="info" :icon="bColumn.icon" size="small"
@click="bColumn.function(scope.row)" ghost>{{ bColumn.label }}</Button>
</span>

<Button v-if="customBtn.doubleEdit" type="info" size="small" @click="beginWithButtonEdit(scope)"
ghost>编辑</Button>
<Button v-if="customBtn.doubleEdit" type="info" size="small" @click="endWithButtonEdit(scope)"
ghost>完成</Button>
</template>
</el-table-column>
</el-table>

LRTableColumn代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template v-if="!column.children || column.children.length == 0">
<el-table-column :prop="column.field" :label="column.title" :min-width="column.width" :formatter="formatter">
<template slot-scope="scope">
<!-- 根据自己的需求进行 -->
</template>
</el-table-column>
</template>
<!-- 递归渲染多级表头 -->
<template v-else>
<el-table-column :label="column.title">
<!-- 子表头 -->
<LRTableColumn v-for="(sub, index) of column.children" :key="index" :column="sub"></LRTableColumn>
</el-table-column>
</template>