目录
概述
CommonTable
组件是一个通用的表格组件,用于展示数据并支持分页、搜索等功能。它可以根据传入的数据和配置灵活地显示表头、分页器、右侧工具栏等元素,支持自定义列的显示与隐藏。
实用性
在一般的后台管理系统中,出现最多的就是表格,通常由头部搜索栏,中间表格核心以及底部分页组件构成。为了简便开发,减少代码量,避免分页组件的引用,以及点击分页时接口的调用,想到写一款Table组件便于平常开发
插槽
header插槽 | 用于放置头部搜索栏 |
other插槽 | 用于放置列表操作栏,比如:新增、导入、导出按钮等 |
table插槽 | 作用域插槽,用于接收搜索或处理之后的表格数据 |
props
pageSizes[Array] | 每页显示个数 |
layout[Array] | 分页器组件布局 |
fetchDataList[function,({current,size})=>{}] | 搜索函数,能获取到分页参数 |
formatDataFun[function,(list)=>{}] | 格式化列表函数,能格式化返回的列表数据 |
immediate[boolean] | 初次加载是否立即搜索 |
showPagination[boolean] | 是否展示分页 |
columns[Array] | 只有在showRight_Tool时生效 |
showColumnsType[String] | 只有在showRight_Tool时生效(checkBox,transfer) |
showRight_Tool[boolean] | 是否展示右侧显隐列tool |
组件源码
<template>
<div class="table-box">
<div v-show="showHeader && showSearch" class="table-box__header">
<slot name="header"></slot>
</div>
<div class="table-box__other">
<div v-if="showOther" class="mb8">
<slot name="other"></slot>
</div>
<div v-if="showRight_Tool" class="mb8">
<right-toolbar
:showSearch.sync="showSearch"
@queryTable="getDataList"
:columns="columns"
:showColumnsType="showColumnsType"
></right-toolbar>
</div>
</div>
<div class="table-box__body" v-loading="loading">
<slot name="table" :tableData="tableData" :columnsData="columns"></slot>
</div>
<el-pagination
v-if="showPagination"
class="table-box__footer"
:current-page="currentPage"
:layout="layout"
:page-size="pageSize"
:page-sizes="pageSizes"
:total="total"
background
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
></el-pagination>
</div>
</template>
<script>
export default {
name: "CommonTable",
props: {
pageSizes: {
type: Array,
default: () => [10, 20, 30, 40],
},
layout: {
type: String,
default: "total, sizes, prev, pager, next, jumper",
},
fetchDataList: {
type: Function,
require: true,
default: () => {},
},
formatDataFun: {
type: Function,
},
immediate: {
type: Boolean,
default: true,
},
showPagination: {
type: Boolean,
default: true,
},
showRight_Tool: {
type: Boolean,
default: true,
},
columns: {
type: Array,
default: () => [],
},
/* 显隐列类型(transfer穿梭框、checkbox复选框) */
showColumnsType: {
type: String,
default: "checkbox",
},
},
data() {
return {
tableData: [],
total: 0,
currentPage: 1,
pageSize: 0,
loading: false,
showSearch: true,
};
},
computed: {
showHeader() {
return !!this.$slots["header"];
},
showOther() {
return !!this.$slots["other"];
},
},
mounted() {
this.pageSize = this.pageSizes[1] || this.pageSizes[0];
if (this.immediate) {
this.getDataList && this.getDataList();
}
},
methods: {
// 请求数据
async getDataList(other = {}, currentPage = 1) {
this.currentPage = currentPage;
const params = {
current: this.currentPage,
// limit: this.pageSize,
size: this.pageSize,
...other,
};
this.loading = true;
try {
const result = await this.fetchDataList(params);
this.loading = false;
let list = [];
// 兼容
if (Array.isArray(result)) {
list = result;
this.total = result.length;
} else if (result?.code === 0) {
const { records, total } = result.data;
list = records;
this.total = parseInt(total);
} else {
list = [];
this.total = 0;
}
if (list.length > 0 && typeof this.formatDataFun === "function") {
list = this.formatDataFun(list);
}
list.forEach(
(item, index) =>
(item._order = (this.currentPage - 1) * this.pageSize + index + 1)
);
// console.log('list', list)
this.tableData = list;
} catch (error) {
console.error(error);
}
this.loading = false;
},
handleSizeChange(newSize) {
this.pageSize = newSize;
this.getDataList({}, this.currentPage);
},
handleCurrentChange(currentPage) {
// this.currentPage = currentPage
this.getDataList({}, currentPage);
},
},
};
</script>
<style lang="scss" scoped>
.table-box {
height: 100%;
display: flex;
flex-direction: column;
&__header {
// padding-bottom: 12px;
}
&__body {
flex: 1;
height: 0px;
::v-deep {
th.el-table__cell {
background-color: #eef0f2;
}
.el-button {
font-size: 14px;
}
}
}
&__other {
display: flex;
align-items: center;
justify-content: space-between;
}
&__footer {
margin-top: 12px;
text-align: right;
}
}
</style>
right-toolbar组件
<template>
<div class="top-right-btn" :style="style">
<el-row>
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top" v-if="search">
<el-button size="mini" circle icon="el-icon-search" @click="toggleSearch()" />
</el-tooltip>
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button size="mini" circle icon="el-icon-refresh" @click="refresh()" />
</el-tooltip>
<el-tooltip class="item" effect="dark" content="显隐列" placement="top" v-if="columns">
<el-button size="mini" circle icon="el-icon-menu" @click="showColumn()" v-if="showColumnsType == 'transfer'"/>
<el-dropdown trigger="click" :hide-on-click="false" style="padding-left: 12px" v-if="showColumnsType == 'checkbox'">
<el-button size="mini" circle icon="el-icon-menu" />
<el-dropdown-menu slot="dropdown">
<template v-for="item in columns">
<el-dropdown-item :key="item.key">
<el-checkbox :checked="item.visible" @change="checkboxChange($event, item.label)" :label="item.label" />
</el-dropdown-item>
</template>
</el-dropdown-menu>
</el-dropdown>
</el-tooltip>
</el-row>
<el-dialog :title="title" :visible.sync="open" append-to-body>
<el-transfer
:titles="['显示', '隐藏']"
v-model="value"
:data="columns"
@change="dataChange"
></el-transfer>
</el-dialog>
</div>
</template>
<script>
export default {
name: "RightToolbar",
data() {
return {
// 显隐数据
value: [],
// 弹出层标题
title: "显示/隐藏",
// 是否显示弹出层
open: false,
};
},
props: {
/* 是否显示检索条件 */
showSearch: {
type: Boolean,
default: true,
},
/* 显隐列信息 */
columns: {
type: Array,
},
/* 是否显示检索图标 */
search: {
type: Boolean,
default: true,
},
/* 显隐列类型(transfer穿梭框、checkbox复选框) */
showColumnsType: {
type: String,
default: "checkbox",
},
/* 右外边距 */
gutter: {
type: Number,
default: 10,
},
},
computed: {
style() {
const ret = {};
if (this.gutter) {
ret.marginRight = `${this.gutter / 2}px`;
}
return ret;
}
},
created() {
if (this.showColumnsType == 'transfer') {
// 显隐列初始默认隐藏列
for (let item in this.columns) {
if (this.columns[item].visible === false) {
this.value.push(parseInt(item));
}
}
}
},
methods: {
// 搜索
toggleSearch() {
this.$emit("update:showSearch", !this.showSearch);
},
// 刷新
refresh() {
this.$emit("queryTable");
},
// 右侧列表元素变化
dataChange(data) {
for (let item in this.columns) {
const key = this.columns[item].key;
this.columns[item].visible = !data.includes(key);
}
},
// 打开显隐列dialog
showColumn() {
this.open = true;
},
// 勾选
checkboxChange(event, label) {
this.columns.filter(item => item.label == label)[0].visible = event;
}
},
};
</script>
<style lang="scss" scoped>
::v-deep .el-transfer__button {
border-radius: 50%;
padding: 12px;
display: block;
margin-left: 0px;
}
::v-deep .el-transfer__button:first-child {
margin-bottom: 10px;
}
</style>
组件实现效果
使用示例代码
<template>
<commonTable
:fetchDataList="fetchDataList"
ref="common-table"
:columns="columns"
>
<template #header>
<el-form
:model="searchObj"
label-suffix=":"
label-width="100px"
:inline="true"
>
<el-form-item label="项目名称" prop="projectName">
<el-input
style="width: 100%"
v-model="searchObj.projectName"
clearable
placeholder="请输入项目名称"
/>
</el-form-item>
<el-form-item label="合同名称" prop="contractName">
<el-input
style="width: 100%"
v-model="searchObj.contractName"
clearable
placeholder="请输入合同名称"
></el-input>
</el-form-item>
<el-form-item>
<el-button
type="primary"
icon="el-icon-search"
size="mini"
@click="handleSearch"
>搜索</el-button
>
<el-button icon="el-icon-refresh" size="mini">重置</el-button>
</el-form-item>
</el-form>
</template>
<template #table="{ tableData, columnsData }">
<el-table :data="tableData" stripe height="100%">
<el-table-column
v-if="columnsData[0].visible"
label="项目名称"
prop="prjName"
></el-table-column>
<el-table-column
v-if="columnsData[1].visible"
label="合同名称"
prop="contractName"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="columnsData[2].visible"
label="创建时间"
prop="createDate"
></el-table-column
></el-table>
</template>
<template #other>
<div>
<el-button type="primary" plain icon="el-icon-plus" size="mini"
>新增</el-button
>
<el-button type="info" icon="el-icon-upload" size="mini"
>导入</el-button
>
<el-button type="info" icon="el-icon-upload2" size="mini"
>导出</el-button
>
</div>
</template>
</commonTable>
</template>
<script>
import commonTable from "./commonTable.vue";
export default {
components: { commonTable },
props: {},
data() {
return {
searchObj: {
contractName: "",
code: "",
projectName: "",
},
columns: [
{ key: 0, label: `项目名称`, prop: "prjName", visible: true },
{ key: 1, label: `合同名称`, prop: "contractName", visible: true },
{ key: 2, label: `创建时间`, prop: "createDate", visible: true },
],
showColumnsType: "transfer",
};
},
watch: {},
computed: {},
methods: {
async fetchDataList(params) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(111); // Just for logging, optional
const data = {
code: 0,
data: {
records: [
{
id: "96",
prjId: "62291648",
contractId: "77735285504",
createBy: "5895203276800",
createDate: "2024-04-01 09:23:49",
prjName: "2017配套道路工程",
contractName:
"配套道路正式外电源监理",
},
{
id: "97",
prjId: "62295021648",
contractId: "777340451328",
createBy: "5893276800",
createDate: "2024-04-09 16:02:26",
prjName: "2017配套道路工程",
contractName:
"道路工程监理(二标段)",
},
{
id: "98",
prjId: "17804657889",
contractId: "1298095218560",
createBy: "110",
createDate: "2024-04-17 16:55:01",
prjName: "园林绿化",
contractName: null,
},
{
id: "99",
prjId: "679611648",
contractId: "77735965617152",
createBy: "4",
createDate: "2024-04-18 12:26:14",
prjName: "配套道路工程",
contractName:
"2017配套道路工程监理",
},
{
id: "100",
prjId: "178079900609",
contractId: "12984063856",
createBy: "110",
createDate: "2024-04-18 14:54:49",
prjName: "项目流程测试1",
contractName: null,
},
{
id: "101",
prjId: "17808557553",
contractId: "129843960576",
createBy: "110",
createDate: "2024-04-18 15:23:21",
prjName: "流程测试项目",
contractName: null,
},
{
id: "102",
prjId: "1780855759153",
contractId: "129845430219008",
createBy: "4",
createDate: "2024-04-18 16:51:17",
prjName: "流程测试项目",
contractName: " 流程测试项目2",
},
{
id: "103",
prjId: "1780467557889",
contractId: "1298463997056",
createBy: "4",
createDate: "2024-04-18 17:27:09",
prjName: "市政基础设施",
contractName: null,
},
{
id: "104",
prjId: "178043374242",
contractId: "1298464701440",
createBy: "4",
createDate: "2024-04-18 17:45:24",
prjName: "wkai@土地一级开发",
contractName: " 土地开发@土地一级开发",
},
{
id: "105",
prjId: "178114366241",
contractId: "1298443776",
createBy: "110",
createDate: "2024-04-19 15:47:34",
prjName: "交付策划路@测试",
contractName: "交付策划@测试",
},
{
id: "106",
prjId: "1782220218882",
contractId: "129977056256",
createBy: "4",
createDate: "2024-04-22 09:52:23",
prjName: "计量支付审批@测试1",
contractName: "计量@测试1",
},
{
id: "107",
prjId: "1782247969",
contractId: "12991513728",
createBy: "4",
createDate: "2024-04-22 14:49:29",
prjName: "计量@测试2",
contractName: null,
},
{
id: "108",
prjId: "17822947969",
contractId: "129933351680",
createBy: "4",
createDate: "2024-04-22 15:05:24",
prjName: "计量@测试2",
contractName: null,
},
{
id: "109",
prjId: "62295029611648",
contractId: "77735091904",
createBy: "4",
createDate: "2024-04-25 15:20:14",
prjName: "道路工程",
contractName:
"电源工程",
},
{
id: "110",
prjId: "178337358466",
contractId: "130129728",
createBy: "110",
createDate: "2024-04-28 15:22:14",
prjName:
"数据走向",
contractName: "ran承包合同经办单位筛选",
},
{
id: "111",
prjId: "178302273",
contractId: "1306566336",
createBy: "4",
createDate: "2024-05-09 17:02:05",
prjName: "房建@学校@测试1",
contractName: "承包学校@测试1",
},
{
id: "112",
prjId: "1783026273",
contractId: "1306027640576",
createBy: "4",
createDate: "2024-05-09 17:21:01",
prjName: "房建测试1",
contractName: "承包合同",
},
{
id: "113",
prjId: "17830257726273",
contractId: "13446626816",
createBy: "4",
createDate: "2024-05-09 18:06:58",
prjName: "学校@测试1",
contractName: "房学校@测试1",
},
{
id: "114",
prjId: "123104",
contractId: "166054912",
createBy: "03276800",
createDate: "2024-05-13 17:17:29",
prjName:
"二类居住用地项目",
contractName: "咨询合同",
},
{
id: "115",
prjId: "98",
contractId: "952",
createBy: "4",
createDate: "2024-05-16 13:41:52",
prjName: "测试",
contractName: "测试",
},
],
total: 57,
},
};
resolve(data);
}, 1000);
});
},
handleSearch() {
this.$refs["common-table"] && this.$refs["common-table"].getDataList();
},
},
created() {},
mounted() {},
};
</script>
<style lang="scss" scoped></style>
结语
CommonTable
组件通过封装常见的数据表格功能和灵活的配置选项,为开发者提供了一个强大而易于使用的工具,能够显著提升数据展示和管理的效率,适用于各种复杂的业务场景和需求。