在日常开发后端管理系统项目中,用于展示数据多会用表格进行展示,这样我们可以把相同的部分处理出来,二次封装一个基于elementUI中的el-table封装一个简单的表格组件,进行多页面的数据展示的复用。
首先第一步肯定要引入elementUI组件库,我们可以使用全局引入和局部引入两种的方式
elementUI具体使用方法可以参考elementUI官网:
Element - The world's most popular Vue UI framework
这边个人推荐使用局部引入,这样可以减少项目的体积
引入之后,接下来我们就可以进行表格的二次封装了:
这个表格有多选框、内容、状态栏、升降序、图片、操作功能
子组件template部分:
<!-- 表格组件 -->
<template>
<el-table
:data="data"
ref="refTable"
style="width: 100%"
:row-key="rowKeyField"
highlight-current-row
:row-class-name="rowClassName"
@select="handleSelection"
@select-all="handleSelectionAll"
@selection-change="handleSelectionChange"
@sort-change="changeTableSort"
@row-click="handleRowClick">
<el-table-column
v-if="showSelect"
type="selection"
width="55"
align="center">
<!-- //TODO showSelect:表格组件是否带多选框类型:带或不带 -->
</el-table-column>
<el-table-column
align="center"
v-for="item in columns"
v-if="typeof item.show === 'undefined' ? true : item.show"
:key="item.prop"
:prop="item.prop"
:label="item.label"
:width="item.width"
:sortable="item.sortable ? 'custom': false"
:formatter="item.formatter">
</el-table-column>
<el-table-column v-if="showStatus" label="状态" align="center">
<!-- // TODO showStatus:是否带状态开关 -->
<template slot-scope="scope">
<el-switch
v-model="scope.row.status"
active-value="0"
inactive-value="1"
@change="handleStatusChange(scope.row)">
</el-switch>
</template>
</el-table-column>
<el-table-column v-if="showImage" :label="imageName ? imageName :
'图片'" align="center" width="300">
<template slot-scope="scope">
<!-- 使用 imagePropertyName 映射到 imageUrl -->
<el-image
v-for="item in scope.row[imagePropertyName]"
:key="item.index"
style="width: 75px; height: 75px; margin-left: 5px;"
:src="item"
:preview-src-list="scope.row[imagePropertyName]"
>
<div
slot="placeholder"
class="image-slot"
style="width: 75px; height: 75px"
>
<img src="@/assets/images/logging.gif" alt="" style="width: 75px; height: 75px" />
</div>
</el-image>
</template>
</el-table-column>
<el-table-column
v-if="showHandle"
fixed="right"
label="操作"
width="150"
align="center">
<!-- //TODO showHandle:是否带操作栏 -->
<template slot-scope="scope">
<slot :item="scope.row"></slot>
</template>
</el-table-column>
</el-table>
</template>
template部分的多选框、状态改变、图片展示、操作栏使用v-if判断是否显示,父组件传入Boolean值选择是否需要,使用示例请看父组件template部分
如果想针对不同角色或状态使表格数据展示不同时,可在父组件的tableColumns中传入show属性来让子组件判断是否展示
在表格中展示图片,需要在父组件中是图片路径转化为数组,并传入图片名
一般表格都会需要操作栏,那么我们使用插槽在子组件中对操作栏进行自定义,父组件中使用插槽添加自己想要的按钮,例子见代码中详情按钮
有时候会需要使用formatter解析表格中的部分参数(对时间进行格式化处理、金额加 $ 符号、后端返回状态对它进行转义展示),需要在子组件中定义formatter方法,让它使用父组件中传入的formatter函数即可,具体可看父组件data中的tableColumns
子组件script部分:
<script>
export default {
props: {
data: {
type: Array,
required: true,
},
columns: {
type: Array,
required: true,
},
rowKeyField: {
type: String,
required: false
},
// 图片展示属性名
imagePropertyName: {
type: String,
required: false,
},
// 图片名
imageName: {
type: String,
required: false,
},
showSelect: {
type: Boolean,
default: false,
},
showHandle: {
type: Boolean,
default: false,
},
showStatus: {
type: Boolean,
defalut: false,
},
showImage: {
type: Boolean,
defalut: false,
},
},
methods: {
//升降序
changeTableSort(column){
this.$emit("tableSort", column);
},
// 清空选择的值
clearSelect() {
this.$refs.refTable.clearSelection();
},
// 根据返回的数据满足过滤条件行高亮显示
rowClassName: function ({ row, rowIndex }) {
let data = "";
this.$emit(
"row-class-name",
{
row: row,
rowIndex: rowIndex,
},
(val) => {
data = val;
}
);
return data; //属性名必须返回一个string
},
handleRowClick(row, column) {
this.$emit("RowClick", row, column);
},
// 选中触发事件
handleSelection(selection, row){
this.$emit("selection", selection,row);
},
// 全选
handleSelectionAll(selection){
this.$emit("selectionAll", selection);
},
// 多选框
handleSelectionChange(val) {
this.$emit("selectionData", val);
},
// 状态开关
handleStatusChange(row) {
let text = row.status === "0" ? "启用" : "停用";
this.$confirm('确认要"' + text + '"吗?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
this.msgSuccess(text + "成功");
// console.log(row);
this.$emit("statusData", row);
})
.catch(function () {
row.status = row.status === "0" ? "1" : "0";
});
},
},
};
</script>
<style lang="scss" scoped>
.el-image {
::v-deep .image-slot {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
color: #909399;
font-size: 30px;
}
</style>
子组件在data中规定父组件传递给子组件数据的类型,默认值等
子组件添加一些基础方法,把值传递给父组件,例如点击多选框后,触发子组件中复选框方法,利用$emit子传父自定义方法名,把选中数据传递给父组件,父组件中调用 @selectionData="getData"
父组件template部分:
<template>
<div class="app-container">
<Table
ref="childTable"
:data="tableData"
:columns="tableColumns"
showSelect
showHandle
showStatus
showImage
v-loading="loading"
:imagePropertyName="pictureName"
:imageName="imageName"
@selection="getSelect"
@selectionAll="getSelectAll"
@selectionData="getSelectData"
@row-class-name="tableRowClassName">
<template slot-scope="{ item }">
<el-button @click="handleTableClick(item)" type="text" size="small">
详情
</el-button>
</template>
</Table>
</div>
</template>
父组件sccript部分:
<script>
import * as Apis from "@/api/comparison/result/index";
import Table from "@/components/DataTable/index"; // 引入组件
import { dateFormat } from "@/utils/index"; // 时间处理函数
export default {
components: { // 使用子组件
Table: Table,
},
data() {
return {
imageName: '证据', // 展示图片名称
pictureName: 'claimReasonPicture', // 图片属性名称
queryParams: {
id: null,
customerNo: "", // 客户编号
contrastResult: "", // 客户状态查询
outOrderNos: [], // 订单号
trackNumbers: [], // 运单号
},
// 加载中遮罩层
loading: false,
tableData: [],
tableColumns: [
{ prop: "customerNo", label: "客户编号", width: "150" },
{ prop: "outOrderNo", label: "客户订单号", show: false },
{ prop: "trackNumber", label: "运单号" },
{
prop: "priceTotal",
label: "总计",
width: "100",
show: false,
formatter: function (row, column, cellValue, index) {
if (row.priceTotal) {
return `$${row.priceTotal}`;
}
},
},
{ prop: "importTime", label: "时间", formatter: dateFormat },
{
prop: "contrastResult",
label: "状态",
formatter: function (row, column, cellValue, index) {
switch (row.contrastResult) {
case 0:
return "已打印";
case 1:
return "未打印";
case -1:
return "运输中";
case -2:
return "已取消";
default:
break;
}
},
},
],
],
};
},
methods: {
// 选择框勾选中
getSelect(selection, row) {
console.log(selection, row);
},
// 选择框全选
getSelectAll(selection) {
console.log(selection);
},
getSelectData(selection) {
console.log(selection);
},
async getList() {
this.loading = true;
const data = await Apis.contrastDetail(this.queryParams);
console.log(data);
this.loading = false;
this.total = data.total;
this.tableData = data.rows;
},
// 详情按钮
handleTableClick(row) {
console.log(row, "当前点击行中的数据");
},
// 行加类名加颜色
tableRowClassName(obj, callback) {
if (obj.row.children) {
callback("success-row");
} else {
callback("");
}
},
},
created() {
this.getList()
},
};
</script>
在父组件data中tableColumns传入formatter方法,就可以对部分数据进行解析、处理。