一共三个组件
- 拖动表格列的顺序:
<template>
<div class="drag-table" :class="{ 'table-moving': dragState.dragging }">
<el-table
ref="table"
v-loading="loading"
element-loading-text="拼命加载中"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(0, 0, 0, 0.8)"
highlight-current-row
size="mini"
:data="data"
:row-key="tableKey"
tooltip-effect="dark"
border
max-height="623"
@selection-change="selectData"
:cell-class-name="cellClassName"
:header-cell-class-name="headerCellClassName"
>
<slot name="table-select"></slot>
<el-table-column
show-overflow-tooltip
v-for="(col, index) in tableHeader"
:key="index"
:prop="col.prop"
:label="col.label"
:width="col.width"
:min-width="col.minWidth"
:type="col.type"
:header-align="col.headerAlign"
:column-key="index.toString()"
:render-header="renderHeader"
>
<template slot-scope="scope">
<slot name="table-body" :data="scope"></slot>
</template>
</el-table-column>
<slot name="table-handle"></slot>
</el-table>
</div>
</template>
<script>
/**
* @author 全易
* @time 2021-04-16 12:39:56 星期五
* @description 拖动表格列的顺序
*/
export default {
name: "TableColumnDrag",
data() {
return {
tableHeader: [],
dragState: {
start: -9, // 起始元素的 index
end: -9, // 移动鼠标时所覆盖的元素 index
dragging: false, // 是否正在拖动
direction: undefined, // 拖动方向
},
};
},
created() {
this.tableHeader =
JSON.parse(localStorage.getItem(this.headId)) || this.header;
},
watch: {
header(val, oldVal) {
this.tableHeader = val;
},
},
props: {
headId: {
type: String,
default: "",
},
loading: {
type: Boolean,
default: true,
},
tableKey: {
type: [String, Number],
default: "",
},
data: {
default: function () {
return [];
},
type: Array,
},
header: {
default: function () {
return [];
},
type: Array,
},
},
methods: {
renderHeader(createElement, { column }) {
return createElement(
"div",
{
class: ["thead-cell"],
on: {
mousedown: ($event) => {
this.handleMouseDown($event, column);
},
mousemove: ($event) => {
this.handleMouseMove($event, column);
},
},
},
[
// 添加 <a> 用于显示表头 label
createElement("span", column.label),
// 添加一个空标签用于显示拖动动画
createElement("span", {
class: ["virtual"],
}),
]
);
},
// 开始拖动
handleMouseDown(e, column) {
this.dragState.dragging = true;
this.dragState.start = parseInt(column.columnKey);
// 给拖动时的虚拟容器添加宽高
let table = document.querySelector(".drag-table");
let virtual = document.getElementsByClassName("virtual");
for (let item of virtual) {
item.style.height = table.clientHeight - 1 + "px";
item.style.width = item.parentElement.parentElement.clientWidth + "px";
}
document.addEventListener("mouseup", this.handleMouseUp);
console.log("1111111111");
},
// 拖动中
handleMouseMove(e, column) {
if (this.dragState.dragging) {
let index = parseInt(column.columnKey); // 记录起始列
if (index - this.dragState.start !== 0) {
this.dragState.direction =
index - this.dragState.start < 0 ? "left" : "right"; // 判断拖动方向
this.dragState.end = parseInt(column.columnKey);
} else {
this.dragState.direction = undefined;
}
} else {
return false;
}
console.log("222222222222");
},
// 拖动易位
dragColumn({ start, end, direction }) {
let tempData = [];
let left = direction === "left";
let min = left ? end : start - 1;
let max = left ? start + 1 : end;
for (let i = 0; i < this.tableHeader.length; i++) {
if (i === end) {
tempData.push(this.tableHeader[start]);
} else if (i > min && i < max) {
tempData.push(this.tableHeader[left ? i - 1 : i + 1]);
} else {
tempData.push(this.tableHeader[i]);
}
}
this.tableHeader = tempData;
console.log("33333333333", this.tableHeader);
localStorage.setItem(this.headId, JSON.stringify(this.tableHeader));
},
// 结束拖动
handleMouseUp() {
this.dragColumn(this.dragState);
// 初始化拖动状态
this.dragState = {
start: -9,
end: -9,
dragging: false,
direction: undefined,
};
document.removeEventListener("mouseup", this.handleMouseUp);
console.log("4444444444");
},
headerCellClassName({ column, columnIndex }) {
let active =
columnIndex === this.dragState.end
? `darg_active_${this.dragState.direction}`
: "";
let start = columnIndex === this.dragState.start ? "darg_start" : "";
return `${active} ${start}`;
},
cellClassName({ column, columnIndex }) {
return columnIndex === this.dragState.start ? "darg_start" : "";
},
// 选择数据
selectData(val) {
// console.log(val);
this.$emit("selectData", val);
},
// 重新渲染表格
resetTable() {
this.$refs.table.doLayout();
},
},
};
</script>
<style lang="less" scoped>
.drag-table {
/deep/.el-table {
.darg_start {
background-color: #f3f3f3;
}
.darg_active_left {
.virtual {
border-left: 2px dotted #666;
z-index: 99;
}
}
.darg_active_right {
.virtual {
border-right: 2px dotted #666;
z-index: 99;
}
}
.virtual {
position: fixed;
display: block;
width: 0;
height: 0;
margin-left: -10px;
background: none;
border: none;
}
.thead-cell {
cursor: grab;
}
}
}
.table-moving {
/deep/.el-table {
.thead-cell {
cursor: e-resize !important;
}
.el-table__fixed {
cursor: not-allowed;
}
}
}
</style>
- 表格增减列:
<template>
<div class="table-column-config">
<el-checkbox
:indeterminate="isIndeterminate"
v-model="isCheckAll"
@change="selectAll"
>全选</el-checkbox
>
<hr />
<el-checkbox-group v-model="defaulte" :min="2" @change="selecting">
<el-checkbox v-for="column in whole" :label="column" :key="column">
{{ column }}
</el-checkbox>
</el-checkbox-group>
</div>
</template>
<script>
/**
* @author 全易
* @time 2021-04-15 09:50:12 星期四
* @description 配置表格列的增减
*/
export default {
name: "TableColumnIncDec",
data() {
return {
isIndeterminate: true,
isCheckAll: false,
original: [],
defaulte: [],
whole: [],
};
},
props: {
dataId: {
type: String,
default: "",
},
now: {
type: Array,
default: [],
},
all: {
type: Array,
default: [],
},
},
watch: {
all: {
handler(now) {
// console.log(now);
this.original = now;
this.whole = now.map((item) => {
return item.label;
});
},
immediate: true,
},
now: {
handler(now) {
// console.log(now);
this.defaulte = now.map((item) => {
return item.label;
});
},
immediate: true,
},
},
methods: {
// 全选
selectAll(val) {
console.log(val);
val ? (this.defaulte = this.whole) : (this.defaulte.length = 2);
this.isIndeterminate = false;
this.configTable();
},
// 单选
selecting(value) {
// console.log(value);
this.defaulte = value;
this.isCheckAll = value.length === this.whole.length;
this.isIndeterminate =
value.length > 0 && value.length < this.whole.length;
this.configTable();
},
// 配置表格
configTable() {
console.log(this.original, this.defaulte);
let result = this.defaulte.map((item) => {
let now;
for (let i = 0, length = this.original.length; i < length; i++) {
if (item === this.original[i].label) {
now = {
label: this.original[i].label,
prop: this.original[i].prop,
};
}
}
// console.log(now);
return now;
});
console.log(result);
console.log(this.dataId);
localStorage.setItem(this.dataId, JSON.stringify(result));
this.$emit("ok", result);
},
},
};
</script>
<style lang="less" scoped>
.el-checkbox-group {
display: grid;
.el-checkbox {
margin-right: 0;
}
}
</style>
- 合并复合表格
记得引入前两个表格
<template>
<div class="custom-table">
<div class="table-handle">
<el-button-group class="functions">
<slot name="function"></slot>
<el-dropdown trigger="click" @command="exporting">
<el-button size="small">
导出<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="1">导出本页</el-dropdown-item>
<el-dropdown-item command="2">导出全部</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-button-group>
<div class="table-config">
<slot name="config"></slot>
<el-popover trigger="manual" v-model="config.show" width="160">
<TableColumnIncDec
:dataId="dataId"
:now="config.nowColumn"
:all="config.allColumn"
@ok="okConfigTable"
/>
<el-button
slot="reference"
size="small"
icon="el-icon-setting"
title="表格配置"
@click="config.show = !config.show"
></el-button>
</el-popover>
</div>
</div>
<TableColumnDrag
ref="table"
:loading="loading"
:headId="headId"
:data="data"
:tableKey="tableKey"
:header="config.nowColumn"
@selectData="selectData"
>
<template v-slot:table-select>
<slot name="select"></slot>
</template>
<template v-slot:table-body="{data}">
<slot name="body" :data="data"></slot>
</template>
<template v-slot:table-handle>
<slot name="handle"></slot>
</template>
</TableColumnDrag>
<el-pagination
@size-change="dataSizeChange"
@current-change="handleCurrentChange"
:page-sizes="[15, 20, 30, 50]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
>
</el-pagination>
</div>
</template>
<script>
/**
* @author 全易
* @time 2021-04-15 14:23:16 星期四
* @description 复合表格
*/
export default {
name: "CustomTable",
data() {
return {};
},
props: {
headId: {
type: String,
default: "",
},
dataId: {
type: String,
default: "",
},
loading: {
type: Boolean,
default: true,
},
data: {
type: Array,
default: [],
},
tableKey: {
type: [String, Number],
default: "",
},
total: {
type: Number,
default: 0,
},
pageSize: {
type: Number,
default: 0,
},
config: {
type: Object,
default: {},
},
},
methods: {
dataSizeChange(val) {
console.log(`每页 ${val} 条`);
this.$emit("dataSize", val);
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`);
this.$emit("handleCurrent", val);
},
// 选择数据
selectData(val) {
// console.log(val);
this.$emit("selectData", val);
},
// 确定配置表格列
okConfigTable(data) {
// console.log(data);
this.config.nowColumn = data;
this.$refs.table.resetTable();
},
// 导出
exporting(command) {
this.$emit("exporting", command);
},
},
};
</script>
<style lang="less" scoped>
</style>
调用:
举个例子
<CustomTable
tableKey="userId"
:loading="loading"
:data="tableData"
:dataId="tableDataId"
:headId="tableHeadId"
:total="total"
:pageSize="queryForm.pageSize"
:config="tableConfig"
@exporting="exporting"
@handleCurrent="handleCurrentChange"
@dataSize="dataSizeChange"
>
<template v-slot:body="{ data }">
<el-popover
v-if="data.column.property === 'avatar'"
trigger="hover"
placement="left"
>
<img
slot="reference"
:src="data.row.avatar"
alt="用户头像"
style="width: 28px; height: 28px"
/>
<img
:src="data.row.avatar"
alt="用户头像"
style="width: 180px; height: 180px"
/>
</el-popover>
<el-tag
v-else-if="data.column.property === 'runStatus'"
:type="data.row.runStatus === '正常' ? 'success' : 'danger'"
>
{{ data.row.runStatus }}
</el-tag>
<span v-else-if="data.column.property === 'userId'">{{
data.row.userId
}}</span>
<span v-else-if="data.column.property === 'loginName'">
{{ data.row.loginName }}
</span>
<span v-else-if="data.column.property === 'userName'">
{{ data.row.userName }}</span
>
<span v-else-if="data.column.property === 'phonenumber'">
{{ data.row.phonenumber }}
</span>
<span v-else-if="data.column.property === 'balance'">
{{ data.row.balance }}
</span>
<span v-else-if="data.column.property === 'integral'">
{{ data.row.integral }}
</span>
</template>
<template v-slot:handle>
<el-table-column label="操作" width="200" fixed="right">
<template slot-scope="scope">
<el-button @click="detail(scope.row)" type="primary" size="mini"
>查看</el-button
>
<el-button
:type="scope.row.runStatus === '正常' ? 'info' : 'danger'"
size="mini"
@click="changeStatus(scope.row)"
>
{{ scope.row.runStatus === "正常" ? "冻结" : "解冻" }}
</el-button>
<el-dropdown
trigger="click"
@command="userHistory($event, scope.row)"
>
<el-button size="small">
记录<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="1">订单记录</el-dropdown-item>
<el-dropdown-item command="2">退款记录</el-dropdown-item>
<el-dropdown-item command="3">提现记录</el-dropdown-item>
<el-dropdown-item command="4">充值记录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-table-column>
</template>
</CustomTable>