# 基于Element Table封装的表格组件
表格是中后台系统里常见的组件, element-ui
中有现成的 table
组件,但是还是需要结合 pagination
使用,为了提高开发效率和组件复用,对组件进行二次封装。
表格中只使用了部分常用功能,因此并不兼容所有配置,可以基于项目再次优化。
🎉 prop配置
|__ ✨ 基本文字
|__ ✨ 文字+说明icon
✨ slot配置
✨ 复选框
✨ 排序
✨ 分页
# 前期
- 准备
基于 Vue
+ typescript
+ stylus
语法
使用了 vue-property-decorator 库
- 需求
要求只需传几个 prop
即可渲染表头,而且支持 slot
自定义表头,内部维护分页信息,同时能通知父级更新数据。
# 开发
- table.vue
<template>
<div class="mt-20">
<el-table
v-loading="tableLoading"
:data="tableData"
:border="border"
v-bind="$attrs"
:class="currentPrefix"
@sort-change="sortChange"
@select-change="selectChange"
>
<template v-for="(column, index) in columns">
<!-- <slot name="front-slot"></slot> -->
<!-- 复选框 -->
<el-table-column v-if="column.type === 'selection'" :key="index" type="selection" width="55" />
<!-- 具体内容 -->
<template v-else>
<el-table-column
:key="index"
:align="column.align || 'center'"
:label="column.title"
:fixed="column.fixed"
:show-overflow-tooltip="column.tooltip"
:min-width="column.minWidth"
:width="column.width"
:sortable="column.sortable"
:prop="column.prop"
>
<template slot="header">
<template v-if="column.headerTip">
<el-tooltip :content="column.headerTip" effect="light" placement="right">
<span>{{ column.title }} <i class="el-icon-warning-outline" style="margin-left:4px;color:#00ad88;font-size:12px;" /></span>
</el-tooltip>
</template>
<template v-else>{{ column.title }}</template>
</template>
<template slot-scope="scope">
<template v-if="!column.slot">
<!-- 操作按钮 -->
<template v-if="column.type === 'operate'">
<el-button
v-for="(operate, a) in column.operates"
:key="a"
:type="operate.type"
:size="operate.size||'mini'"
plain
@click="handleClick(operate, scope.$index, scope.row)"
>{{ operate.name }}</el-button>
</template>
<span v-else>{{ scope.row[column.key] }}</span>
</template>
<!-- 使用slot的情况下 -->
<template v-else>
<slot :name="column.slot" :scope="scope" />
</template>
</template>
</el-table-column>
</template>
</template>
<!--默认的slot -->
<slot />
</el-table>
<el-pagination
v-if="showPagination && tableData.length > 0"
background
:current-page="syncedPage"
:layout="layout"
:total="totalCount"
:page-size="syncedPageSize"
:page-sizes="pageSizes"
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
/>
</div>
</template>
<script lang="ts">
import { Vue, Component, Prop, PropSync, Emit } from 'vue-property-decorator'
import Mixin from '@/mixin'
@Component
export default class BaseTable extends Vue {
constructor() {
super()
this.currentPrefix = 'base-table'
}
@Prop({
default: false
})
tableLoading!: boolean
@Prop({
default() {
return []
}
})
tableData!: any
@Prop({
default() {
return []
},
required: true
})
columns!: any
@Prop({
default: true
})
showPagination!: boolean
@Prop({
default: 'total, sizes, prev, pager, next, jumper'
})
layout!: string
@PropSync('page', {
type: Number,
default: 1
})
syncedPage!: number
@PropSync('pageSize', {
type: Number,
default: 10
})
syncedPageSize!: number
@Prop({
default() {
return [10, 20, 30, 40, 50, 100]
}
})
pageSizes!: any
@Prop({
default: 0
})
totalCount!: number
@Prop({
default: true
})
border!: boolean
private pagination: any = {}
@Emit()
private sortChange(column: any, prop: any, order: any) {}
@Emit()
private selectChange(selection: any) {}
@Emit('getData')
private handleCurrentChange(_val: number) {
this.pagination.page = _val
this.syncedPage = _val
}
private handleSizeChange(_val: number) {
this.pagination.pageSize = _val
this.syncedPageSize = _val
this.handleCurrentChange(1)
}
private handleClick(action: any, index: number, data: any) {
this.$emit(`${ action.emitKey }`, index, data)
}
}
</script>
<style lang="stylus" scoped>
$prefix = base-table
.{$prefix} {
width 100%;
}
</style>
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# 使用
- mixin
把列表中通用字段,写到 mixin
,页面结合 tableMixin
使用。
定义了统一的获取数据方法 getTableData
,表格数据 tableData
,分页模板 page
tableLoading
是可选的,如果需要即在调用api前标记为 true
,调用完毕重置为 false
即可。
import { Component, Vue } from 'vue-property-decorator'
@Component
class tableMixin extends Vue {
[x: string]: any
public tableData: any = []
public tableLoading: boolean = false
public page = {
PageSize: 10,
PageIndex: 1
}
public totalCount: number = 0
public handleCurrentChange(PageIndex: number = 1) {
this.page.PageIndex = PageIndex
this.getTableData()
}
}
export default tableMixin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- 示例
private headers: any = [
{
key: 'Name',
title: '服务项目名称',
headerTip: '这是表头的提示文字' // 表头文字说明,el-tooltip悬浮显示
},
{
key: 'CreatedTime',
title: '创建时间'
},
{
slot: 'status',
title: '状态'
},
{
slot: 'operate',
title: '操作',
width: '280'
}
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
key,直接使用,对应列内容的字段名
slot,自定义列的内容。定义一个名称,然后在 base-table
里写相关slot
<base-table
:table-loading="tableLoading"
:table-data="tableData"
:columns="headers"
:total-count="totalCount"
:page.sync="page.PageIndex"
:page-size.sync="page.PageSize"
@getData="getTableData"
>
<template slot="status" slot-scope="{scope}">
<div>{{ scope.row.IsEnable ? '启用' : '禁用' }}</div>
</template>
</base-table>
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 最后
基本思路和代码如上,可以根据项目实际情况,加上其他 table
的配置,还可以设置为全局组件和 mixin
,避免每个页面导入等。
← Vue优化 卡片式轮播图之后台实现 →