前言
使用配置描述数据来替代 vue 模板的组件写法,基础能力完全与 el-table 组件保持一致。并提供了一些方便和自定义的 api,加快书写。
代码实现
<script>
import { formatDate } from 'element-ui/lib/utils/date-util';
function isObject (obj) {
return Object.prototype.toString.call(obj) === '[object Object]';
};
function isNil (val) {
return val === undefined || val === null;
};
function getEnumValue (value, _enum) {
const valueEnum = _enum || undefined;
return valueEnum && valueEnum[value] ? valueEnum[value] : value;
};
export default {
name: 'ElProTable',
props: {
data: {
type: Array,
default: () => ([])
},
columns: {
type: Array,
default: () => ([])
},
loading: Boolean
},
mounted () {
this.mountTableMethods();
},
methods: {
// 在 this 上挂载 table 组件实例方法
mountTableMethods() {
const ElTableMethodKeys = ['clearSelection', 'toggleRowSelection', 'toggleAllSelection', 'toggleRowExpansion', 'setCurrentRow', 'clearSort', 'clearFilter', 'doLayout', 'sort'];
Object.entries(this.$refs.table).forEach(([key, item]) => {
if (ElTableMethodKeys.includes(key)) {
this[key] = item;
}
});
},
generateValue ({ prop, valueType, enum: _enum }) {
if (!prop) return null;
return (scoped) => {
const row = scoped.row || {};
let value = row[prop];
switch (valueType) {
case 'date':
value = formatDate(value);
break;
case 'dateTime':
value = formatDate(value, 'yyyy-MM-dd HH:mm:ss');
break;
case 'text':
default: value = getEnumValue(value, _enum);
};
return value;
};
},
renderColumns (h, columns) {
const $scopedSlots = this.$scopedSlots;
return columns.map((item, i) => {
if (!isObject(item)) return null;
const key = !isNil(item.prop) ? item.prop : i;
const { render, renderHeader, slot, slotHeader, columns: _columns, ...props } = item;
const scopedSlots = {
default: render ? (scoped) => render(h, scoped) : $scopedSlots[slot] || this.generateValue(item),
header: renderHeader ? (scoped) => renderHeader(h, scoped) : $scopedSlots[slotHeader] || null
};
// 通过递归处理多级表头的情况
return <el-table-column key={ key } { ...{ props } } scopedSlots={ scopedSlots }>
{ Array.isArray(_columns) ? this.renderColumns(h, _columns) : null }
</el-table-column>;
});
}
},
render (h) {
return (
<div class="el-pro-table">
<el-table
ref="table"
{ ...{ props: this.$attrs } }
{ ...{ on: this.$listeners } }
data={ this.data }
v-loading={ this.loading }
>
{ this.renderColumns(h, this.columns) }
</el-table>
</div>
);
}
};
</script>
基本使用
<template>
<el-pro-table :data="dataSource" :columns="columns" />
</template>
<script>
export default {
data () {
return {
columns: [
{
prop: 'name',
label: 'Name'
},
{
prop: 'age',
label: 'Age'
},
{
prop: 'address',
label: 'Address'
}
],
dataSource: [
{ name: 'Yu Lou', age: 32, address: 'New York No. 1 Lake Park' },
{ name: 'Jim Green', age: 42, address: 'London No. 1 Lake Park' },
{ name: 'Joe Black', age: 32, address: 'Sidney No. 1 Lake Park' },
]
}
}
}
</script>
使用 valueType
封装了一些常用的值类型来减少重复的 render 操作,通过在 columns 数据项中配置一个 valueType 即可展示格式化的数据。
<template>
<el-pro-table :data="dataSource" :columns="columns" />
</template>
<script>
export default {
data () {
return {
columns: [
{
prop: 'title',
label: 'Title'
},
{
prop: 'createTime',
label: 'Time',
valueType: 'dateTime'
},
{
prop: 'state',
label: 'State'
},
],
dataSource: [
{ title: 'title 1', createTime: 1616495706550, state: 'open' },
{ title: 'title 2', createTime: 1616405700550, state: 'closed' },
]
}
}
}
</script>
使用 enum
通过在 columns 数据项中配置 enum 对象,将状态值转为对应的描述。
<template>
<el-pro-table :data="dataSource" :columns="columns" />
</template>
<script>
export default {
data () {
return {
columns: [
{
prop: 'title',
label: 'Title'
},
{
prop: 'state',
label: 'State',
enum: {
open: '未解决',
closed: '已解决'
}
},
],
dataSource: [
{ title: 'title 1', state: 'open' },
{ title: 'title 2', state: 'closed' },
]
}
}
}
</script>
自定义列
render 写法
通过给 columns 数据的项,设置一个函数 render,可以自定义渲染当前列,包括渲染自定义组件,它基于 Vue 的 Render 函数。
render 函数传入两个参数,第一个是 h,第二个是对象,包含 row、column 和 $index,分别指当前行数据,当前列数据,当前是第几行。
<template>
<el-pro-table :data="dataSource" :columns="columns" />
</template>
<script>
export default {
data () {
return {
columns: [
{
prop: 'name',
label: 'Name'
},
{
prop: 'age',
label: 'Age'
},
{
prop: 'address',
label: 'Address'
},
{
label: 'Action',
render (h, { row }) {
return (
<div>
<el-button type="text">Invite { row.name }</el-button>
<el-button type="text">Delete</el-button>
</div>
)
}
}
],
dataSource: [
{ name: 'Yu Lou', age: 32, address: 'New York No. 1 Lake Park' },
{ name: 'Jim Green', age: 42, address: 'London No. 1 Lake Park' },
{ name: 'Joe Black', age: 32, address: 'Sidney No. 1 Lake Park' },
]
}
}
}
</script>
slot-scope 写法
在 columns 的某列声明 slot 后,就可以在 Table 的 slot 中使用 slot-scope。
slot-scope 的参数有 3 个:当前行数据 row,当前列数据 column,当前行序号 $index。
<template>
<el-pro-table :data="dataSource" :columns="columns">
<template slot-scope="{ row }" slot="action">
<el-button type="text">Invite {{ row.name }}</el-button>
<el-button type="text">Delete</el-button>
</template>
</el-pro-table>
</template>
<script>
export default {
data () {
return {
columns: [
{
prop: 'name',
label: 'Name'
},
{
prop: 'age',
label: 'Age'
},
{
prop: 'address',
label: 'Address'
},
{
label: 'Action',
slot: 'action'
}
],
dataSource: [
{ name: 'Yu Lou', age: 32, address: 'New York No. 1 Lake Park' },
{ name: 'Jim Green', age: 42, address: 'London No. 1 Lake Park' },
{ name: 'Joe Black', age: 32, address: 'Sidney No. 1 Lake Park' },
]
}
}
}
</script>
自定义表头
render 写法
通过给 columns 数据的项,设置一个函数 renderHeader,可以自定义渲染当前列表头,包括渲染自定义组件,它基于 Vue 的 Render 函数。
renderHeader 函数传入两个参数,第一个是 h,第二个是对象,包含 column 和 $index,分别指当前列数据,当前是第几行。
<template>
<el-pro-table :data="tableData" :columns="columns" />
</template>
<script>
export default {
data () {
return {
search: '',
columns: [
{
prop: 'date',
label: 'Date'
},
{
prop: 'name',
label: 'Name'
},
{
align: 'right',
renderHeader: (h, scoped) => {
return <el-input value={ this.search } on-input={ this.onInput } size="small" placeholder="Search" />
},
render (h) {
return <el-button size="small">Edit</el-button>
}
}
],
dataSource: [
{ date: '2016-05-03', name: 'Yu Lou' },
{ date: '2016-05-02', name: 'Jim Green' },
{ date: '2016-05-04', name: 'Joe Black' }
]
}
},
computed: {
tableData () {
const { dataSource, search } = this
return dataSource.filter(data => !search || data.name.toLowerCase().includes(search.toLowerCase()))
}
},
methods: {
onInput (value) {
this.search = value
}
}
}
</script>
slot-scope 写法
在 columns 的某列声明 slotHeader 后,就可以在 Table 的 slot 中使用 slot-scope。
slot-scope 的参数有 3 个:当前行数据 row,当前列数据 column,当前行序号 $index。
<template>
<el-pro-table :data="tableData" :columns="columns">
<template slot-scope="scope" slot="search">
<el-input v-model="search" size="small" placeholder="Search" />
</template>
<template slot-scope="scope" slot="action">
<el-button size="small">Edit</el-button>
</template>
</el-pro-table>
</template>
<script>
export default {
data () {
return {
search: '',
columns: [
{
prop: 'date',
label: 'Date'
},
{
prop: 'name',
label: 'Name'
},
{
align: 'right',
slotHeader: 'search',
slot: 'action'
}
],
dataSource: [
{ date: '2016-05-03', name: 'Yu Lou' },
{ date: '2016-05-02', name: 'Jim Green' },
{ date: '2016-05-04', name: 'Joe Black' }
]
}
},
computed: {
tableData () {
const { dataSource, search } = this
return dataSource.filter(data => !search || data.name.toLowerCase().includes(search.toLowerCase()))
}
}
}
</script>
多级表头
在 columns 配置项中可以内嵌 columns,以渲染多级表头。
<template>
<el-pro-table :data="dataSource" :columns="columns" />
</template>
<script>
export default {
data () {
return {
columns: [
{
prop: 'date',
label: '日期',
width: '150'
},
{
label: '配送信息',
columns: [
{
prop: 'name',
label: '姓名',
width: '120'
},
{
label: '地址',
columns: [
{
prop: 'province',
label: '省份',
width: '120'
},
{
prop: 'city',
label: '市区',
width: '120'
},
{
prop: 'address',
label: '详细地址'
},
{
prop: 'zip',
label: '邮编',
width: '120'
}
]
},
]
}
],
dataSource: [
{ date: '2016-05-03', name: 'Yu Lou', province: '浙江省', city: '杭州市', address: 'Fu Ding No. 1 Lake Park', zip: 200333 },
{ date: '2016-05-02', name: 'Yu Lou', province: '浙江省', city: '杭州市', address: 'Fu Ding No. 1 Lake Park', zip: 200333 },
{ date: '2016-05-04', name: 'Yu Lou', province: '浙江省', city: '杭州市', address: 'Fu Ding No. 1 Lake Park', zip: 200333 },
{ date: '2016-05-01', name: 'Yu Lou', province: '浙江省', city: '杭州市', address: 'Fu Ding No. 1 Lake Park', zip: 200333 },
{ date: '2016-05-08', name: 'Yu Lou', province: '浙江省', city: '杭州市', address: 'Fu Ding No. 1 Lake Park', zip: 200333 },
{ date: '2016-05-08', name: 'Yu Lou', province: '浙江省', city: '杭州市', address: 'Fu Ding No. 1 Lake Park', zip: 200333 },
{ date: '2016-05-08', name: 'Yu Lou', province: '浙江省', city: '杭州市', address: 'Fu Ding No. 1 Lake Park', zip: 200333 }
]
}
},
}
</script>
Table Props
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
columns | 表格列的配置描述,详见 column 配置 | array | - | - |
data | 显示的数据 | array | - | - |
loading | 是否加载中 | boolean | - | false |
... | 其他 el-table 组件支持的属性 | - | - | - |
Column
列描述数据对象。column 支持 el-table-column 已有的 props 配置,但是也提供了一些方便和自定义的 api,加快书写:
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
render | 自定义渲染列,使用 Vue 的 Render 函数。传入两个参数,第一个是 h,第二个为对象,包含 row、column 和 index,分别指当前行数据,当前列数据,当前行索引,详见示例 | function | - | - |
renderHeader | 自定义列头显示内容,使用 Vue 的 Render 函数。传入两个参数,第一个是 h,第二个为对象,包含 column 和 index,分别指当前行数据,当前列数据,当前行索引,详见示例 | function | - | - |
slot | 与 slot-scope 结合使用,自定义渲染列 | string | - | - |
slotHeader | 与 slot-scope 结合使用,自定义列头 | string | - | - |
valueType | 当前列值的类型,详见 valueType 配置 | string | text / date / dateTime | text |
enum | 当前列值的枚举 | object | - | - |
render、slot、valueType、enum 同时配置时,会有渲染优先级。render 渲染级别最高。一般情况下:render > slot > valueType / enum。配置自定义 header 时同理。
ValueType
封装了一些常用的值类型来减少重复的 render 操作,配置一个 valueType 即可展示格式化响应的数据。
属性 | 描述 |
---|---|
text | 普通的文本类型 |
date | 当数据是日期类型的返回时,会自动将格式转换为 '2020-10-20' |
dateTime | 当数据是日期类型的返回时,会自动将格式转换为 '2020-10-20 19:30:00' |
... | 陆续添加中 |
Table Events
事件名称 | 说明 | 回调参数 |
---|---|---|
... | el-table 组件支持的事件 | - |
Table Methods
支持 el-table 所有的 methods.