应用场景:在编写后台管理系统时,常常会用到表格和翻页器,每次都需要重复的写很麻烦,并且普通表格只需要渲染对应的prop就可以了,完全可以用一个v-for判断去解决,因此一个自带翻页器的table组件就应运而生了
实现功能:
- 在渲染表格时,只需要传递列表配置即可无脑渲染,无需疯狂cv然后改一些鸡毛蒜皮的小东西
- 根据字段判断是否自定义插槽,使用具名插槽去单独编译
- 分页器和翻页的方法都绑定到同一个方法,父组件接收一个渲染列表的方法即可
- 有JSX和template两种写法,各取所需(vue2版本)
一、tamplate写法
<template>
<div class="hc-table">
<el-table
ref="filterTable"
:row-class-name="tableRowClassName"
v-loading="loading"
:data="tableData"
:cell-style="cellStyle"
@sort-change="sortChange"
>
<template v-for="(item, index) in columns">
<!-- solt 自定义列-->
<!--
自定义列的使用方法:
在使用插槽时#后跟slotType
<template #createTime="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
-->
<template v-if="item.type === 'slot'">
<el-table-column
:class-name="item.class"
:key="index"
:width="item.width"
:prop="item.prop"
:label="item.label"
:align="item.align ? item.align : 'center'"
>
<template slot-scope="scope">
<slot :name="item.slotType" :row="scope.row"/>
</template>
</el-table-column>
</template>
<!--普通表格-->
<template v-else>
<el-table-column
:show-overflow-tooltip="item.showOverflowTooltip||true"
v-if="item.visible !== false"
:key="index"
:sortable="item.sortable"
:prop="item.prop"
:label="item.label"
:align="item.align ? item.align : 'center'"
:width="item.width"
></el-table-column>
</template>
</template>
</el-table>
<div class="pagination-container" v-if="showPagination">
<el-pagination
:background="background"
:current-page.sync="currentPage"
:page-size.sync="pageSize"
:layout="layout"
:page-sizes="pageSizes"
:pager-count="pagerCount"
:total="total"
v-bind="$attrs"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</div>
</template>
<script>
import { scrollTo } from '@/utils/scroll-to'
export default {
name: 'HcTable',
props: {
// 表单数据
tableData: Array,
// 数据列表配置
columns: Array,
// 行样式
tableRowClassName: Function,
// 加载状态
loading: Boolean,
// 单元格的 style 的回调方法
cellStyle: Function,
// 是否展示翻页组件
showPagination: { type: Boolean, default: true },
// 总数
total: Number,
// pagination的page
page: Number,
// pagination的limit
limit: Number,
pageSizes: {
type: Array,
default() {
return [10, 20, 30, 50]
}
},
// 移动端页码按钮的数量端默认值5
pagerCount: {
type: Number,
default: document.body.clientWidth < 992 ? 5 : 7
},
layout: {
type: String,
default: 'total, sizes, prev, pager, next, jumper'
},
background: {
type: Boolean,
default: true
},
autoScroll: {
type: Boolean,
default: true
},
hidden: {
type: Boolean,
default: false
}
},
computed: {
currentPage: {
get() {
return this.page
},
set(val) {
this.$emit('update:page', val)
}
},
pageSize: {
get() {
return this.limit
},
set(val) {
this.$emit('update:limit', val)
}
}
},
methods: {
sortChange(filters) {
this.$emit('sortChange', filters)
},
handleSizeChange(val) {
if (this.currentPage * val > this.total) {
this.currentPage = 1
}
this.$emit('pagination', { page: this.currentPage, limit: val })
},
handleCurrentChange(val) {
this.$emit('pagination', { page: val, limit: this.pageSize })
}
}
}
</script>
<style scoped>
.pagination-container {
background: #fff;
padding: 32px 16px;
}
.pagination-container.hidden {
display: none;
}
</style>
二、JSX写法
<script>
export default {
name: 'HcTable',
props: {
// 表单数据
tableData: Array,
// 数据列表配置
columns: Array,
// 行样式
tableRowClassName: Function,
// 加载状态
loading: Boolean,
// 单元格的 style 的回调方法
cellStyle: Function,
// 是否展示翻页组件
showPagination: { type: Boolean, default: true },
// 总数
total: Number,
// pagination的page
page: Number,
// pagination的limit
limit: Number,
pageSizes: {
type: Array,
default() {
return [10, 20, 30, 50]
}
},
// 移动端页码按钮的数量端默认值5
pagerCount: {
type: Number,
default: document.body.clientWidth < 992 ? 5 : 7
},
layout: {
type: String,
default: 'total, sizes, prev, pager, next, jumper'
},
background: {
type: Boolean,
default: true
},
autoScroll: {
type: Boolean,
default: true
},
hidden: {
type: Boolean,
default: false
}
},
computed: {
currentPage: {
get() {
return this.page
},
set(val) {
this.$emit('update:page', val)
}
},
pageSize: {
get() {
return this.limit
},
set(val) {
this.$emit('update:limit', val)
}
}
},
methods: {
sortChange(filters) {
this.$emit('sortChange', filters)
},
handleSizeChange(val) {
if (this.currentPage * val > this.total) {
this.currentPage = 1
}
this.$emit('pagination', { page: this.currentPage, limit: val })
},
handleCurrentChange(val) {
this.$emit('pagination', { page: val, limit: this.pageSize })
},
renderTable() {
const { tableRowClassName, loading, tableData, cellStyle, sortChange } = this
return <el-table
ref="filterTable"
row-class-name={tableRowClassName}
v-loading={loading}
data={tableData}
cell-style={cellStyle}
on-sort-change={sortChange}
>
{this.columns.map((item, index) =>
this.renderTableColumn(item, index))}
</el-table>
},
renderTableColumn(item, index) {
if (item.visible === false) return
if (item.type === 'slot') {
/* solt 自定义列
自定义列的使用方法:
在使用插槽时#后跟slotType
*/
return <el-table-column
class-name={item.class}
key={index}
width={item.width}
prop={item.prop}
label={item.label}
align={item.align ? item.align : 'center'}
formatter={(row) => {
return this.$scopedSlots[item.slotType]({
row: row
})
}}
>
</el-table-column>
} else {
// 普通表格
return <el-table-column
show-overflow-tooltip={item.showOverflowTooltip || true}
key={index}
sortable={item.sortable}
prop={item.prop}
label={item.label}
align={item.align ? item.align : 'center'}
width={item.width}
></el-table-column>
}
},
renderPagination() {
const {
showPagination,
pageSizes,
pagerCount,
total,
layout,
currentPage,
pageSize,
handleSizeChange,
handleCurrentChange,
background
} = this
const listeners = { // 关键代码 - 1
'update:current-page': val => {
this.currentPage = val
},
'update:limit': val => {
this.pageSize = val
}
}
if (showPagination && total > 0) {
return <div class="pagination-container">
<el-pagination
background={background}
current-page={currentPage}
page-size={pageSize}
layout={layout}
page-sizes={pageSizes}
pager-count={pagerCount}
total={total}
{...{ on: listeners }}
on-size-change={handleSizeChange}
on-current-change={handleCurrentChange}
/>
</div>
}
}
},
render(createElement, context) {
return <div class="hc-table">{this.renderTable()}{this.renderPagination()}</div>
}
}
</script>
<style scoped>
.pagination-container {
background: #fff;
padding: 32px 16px;
}
.pagination-container.hidden {
display: none;
}
</style>
三、使用方法
示例:
<hc-table :loading="loading" :tableData="userList" :columns="columns" :total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize" @pagination="getList"
>
<template #statusStr="scope">
{{ scope.row.status == 0 ? '正常' :'停用' }}
</template>
<template #operate="scope">
<el-button
size="mini"
type="text"
@click="handleUpdate(scope.row,'reset')"
>重置密码
</el-button>
<el-button
size="mini"
type="text"
@click="handleUpdate(scope.row,'edit')"
>修改
</el-button>
<el-button
size="mini"
type="text"
class="color_red"
@click="handleDelete(scope.row)"
>删除
</el-button>
</template>
</hc-table>
// data中的columns列信息配置如下
columns: [
{ prop: 'userId', label: `序号` },
{ prop: 'userName', label: `账户名称` },
{ label: `状态`,type: 'slot',slotType:'statusStr' },
{
class: 'small-padding fixed-width',
width: '160',
label: `操作`,
type: 'slot',
slotType: 'operate'
}
],