elementui表格二次封装(带有表头显示元素拖拽功能、分页功能),可直接引入使用

本文介绍了如何使用Table.vue组件实现表格的列自定义过滤功能,并展示了如何配置列显示、排序、筛选和分页。通过CTableColumnFilter组件,用户可以动态调整列隐藏状态,提高数据展示灵活性。
摘要由CSDN通过智能技术生成

Table.vue

<template>
	<div class="table-wrapper">
		<div class="actions-wrapper">
			<slot name="actions"></slot>
			<el-button icon="el-icon-setting" size="mini" @click="visible = true" v-if="$props.filterColumn">
				显示元素
			</el-button>
		</div>
		<div class="elTable-wrapper">
			<template>
				<el-table height="100%" :key="tableId" :data="data ? data[$props.props.content] : []"
					:highlight-current-row="highlightCurrentRow" @selection-change="selectionChange"
					@current-change="handleCurrentChange" v-loading="loading" :element-loading-text="btnLoadingLabel"
					:border="border" :stripe="stripe" :show-overflow-tooltip="showOverflowTooltip"
					:max-height="maxHeight" :size="size" :align="align" :ref="`table${$route.path}`" style="width:100%">
					<el-table-column type="selection" width="55" v-if="showBatchDelete"></el-table-column>
					<template v-for="column in tableColumns">
						<el-table-column header-align="left" align="left" :prop="column.prop" :label="column.label"
							:width="column.width" :min-width="column.minWidth" :fixed="column.fixed" :key="column.prop"
							:type="column.type" :formatter="column.formatter"
							:sortable="column.sortable == null ? false : column.sortable" v-if="!column.hide">
							<span slot-scope="{ row }">
								<span v-if="column.slotScope">
									<slot :name="column.slotScope.slot" :row="row" />
								</span>
								<span v-else> {{row[column.prop]}} </span>
							</span>
							
						</el-table-column>
					</template>
					<slot></slot>
				</el-table>
			</template>
		</div>
		<div class="pagination-wrapper" v-if="data && data[$props.props.totalSize] > 0">
			<el-pagination layout="total, sizes, prev, pager, next, jumper" :page-sizes="[3,10, 20, 50, 100, 300, 500]"
				@current-change="handlePageChange" :current-page="page" :page-size="pageSize"
				@size-change="handleSizeChange" :total="data ? data[$props.props.totalSize] : 0">
			</el-pagination>
		</div>
		<c-table-column-filter v-if="visible" :columns="currentColumn" @columns-change="handleColumnsChange"
			@close="visible = false" />
	</div>
</template>

<script>
	import CTableColumnFilter from "./TableColumnFilter";
	export default {
		components: {
			CTableColumnFilter
		},
		props: {
			columns: Array, // 表格列配置
			data: Object, // 表格分页数据
			props: {
				type: Object,
				default: () => {
					return {
						content: "content",
						totalSize: "totalSize"
					};
				}
			},
			size: {
				// 尺寸样式
				type: String,
				default: "mini"
			},
			align: {
				// 文本对齐方式
				type: String,
				default: "left"
			},
			maxHeight: {
				// 表格最大高度
				type: Number,
				default: 800
			},
			minHeight: {
				// 表格最小高度
				type: Number,
				default: 180
			},
			// heights: {
			//   // 表格高度
			//   type: String,
			//   default: "auto"
			// },
			border: {
				// 是否显示边框
				type: Boolean,
				default: false
			},
			stripe: {
				// 是否显示斑马线
				type: Boolean,
				default: true
			},
			highlightCurrentRow: {
				// // 是否高亮当前行
				type: Boolean,
				default: false
			},
			showOverflowTooltip: {
				// 是否单行显示
				type: Boolean,
				default: true
			},
			showBatchDelete: {
				// 是否显示操作组件
				type: Boolean,
				default: true
			},
			loading: {
				type: Boolean,
				default: false
			},
			btnLoadingLabel: {
				type: String,
				default: "加载中..."
			},
			page: {
				type: Number,
				default: 1
			},
			pageSize: {
				type: Number,
				default: 20
			},
			filterColumn: {
				type: Boolean,
				default: false
			}
		},
		data() {
			return {
				selections: [], // 列表选中列
				visible: false,
				currentColumn: [],
				tableId: new Date().getTime()
			};
		},
		computed: {
			tableColumns() {
				const props = this.currentColumn.map(
				  item => `${item.prop}-${item.label}`
				);
				const list = new Array(props.length).fill(null);

				this.$props.columns.map((column, columnIndex) => {
					const index = props.indexOf(`${column.prop}-${column.label}`);
					if (index >= 0) {
						list[index] = {
							...column,
							...this.currentColumn[index]
						};
					} else {
						const hide = column.hide != undefined ? column.hide : false;
						const isExport = column.export != undefined ? column.export : false;
						list.push({
							...column,
							hide,
							export: isExport
						});
					}
				});
				list.forEach((item, index) => {
					if (!item) {
						list.splice(index, 1);
					}
				});
				return list;
			}
		},
		methods: {
			// 选择切换
			selectionChange: function(selections) {
				this.selections = selections;
				this.$emit("selection-change", selections);
			},
			// 选择切换
			handleCurrentChange: function(val) {
				this.$emit("current-change", val);
			},
			// 换页刷新
			handlePageChange: function(pageNum) {
				this.$emit("page-change", pageNum);
			},
			//
			handleSizeChange(size) {
				this.$emit("size-change", size);
			},
			handleColumnsChange(column) {
				this.currentColumn = column;
				let history = localStorage.getItem("columnOption");
				history ? (history = JSON.parse(history)) : (history = {});
				const key = this.$route.path;
				history[key] = column;
				localStorage.setItem("columnOption", JSON.stringify(history));
				this.visible = false;
				this.tableId = new Date().getTime();
			},
			getColumnSetting() {
				if (!this.$props.filterColumn) {
					this.currentColumn = this.$props.columns.map(item => {
							return {
								label: item.label,
								prop: item.prop,
								hide: item.hide,
								export: false
							};

					});
					return false;
				}

				let history = localStorage.getItem(`columnOption`);
				history ? (history = JSON.parse(history)) : (history = {});
				const historyCurrentTable = history[this.$route.path];
				if (!historyCurrentTable) {
					this.currentColumn = this.$props.columns.map(item => {
						return {
							label: item.label,
							prop: item.prop,
							hide: item.hide,
							export: false
						};
						
					});
					return false;
				}
				const historyColumns = historyCurrentTable.map(item => {
					return `${item.prop}-${item.label}`;
					
				});
				let container = new Array(historyColumns.length).fill(null);
				this.$props.columns.forEach((column, columnIndex) => {
					const index = historyColumns.indexOf(`${column.prop}-${column.label}`);
					if (index >= 0) {
						container[index] = {
							...column,
							...historyCurrentTable[index]
						};
					} else {
						const hide = column.hide != undefined ? column.hide : false;
						const isExport = column.export != undefined ? column.export : false;
						container.push({
							...column,
							hide,
							export: isExport
						});
					}
				});
				container.forEach((item, index) => {
					if (!item) {
						container.splice(index, 1);
					}
				});
				this.currentColumn = container;
			}
		},
		created() {
			this.getColumnSetting();
		}
	};
</script>

<style lang="scss" scoped>
	.actions-wrapper {
		margin-bottom: 10px;
		margin: 10px;
	}

	.pagination-wrapper {
		margin-top: 20px;
		display: flex;
		justify-content: flex-end;
	}
</style>

TableColumnFilter.vue

<template>
	<el-dialog title="显示元素" :visible="true" width="500px" @close="$emit('close')">
		<div class="table">
			<div class="table-row">
				<div class="table-cell">排序</div>
				<div class="table-cell">列表名称</div>
				<div class="table-cell">是否显示</div>
			</div>
			<!-- 拖拽插件 -->
			<vuedraggable v-model="tableData">
				<!-- 过度效果 -->
				<transition-group>
					<div class="table-row" v-for="(item, index) in tableData" :key="item.label">
						<div class="table-cell">{{ index + 1 }}</div>
						<div class="table-cell">{{ item.label }}</div>
						<div class="table-cell">
							<el-switch v-model="item.hide"></el-switch>
						</div>
					</div>
				</transition-group>
			</vuedraggable>
		</div>
		<div class="actions-wrapper" slot="footer">
			<el-button size="small" @click="$emit('close')">取消</el-button>
			<el-button type="primary" size="small" @click="save">
				保存
			</el-button>
		</div>
	</el-dialog>
</template>

<script>
	import vuedraggable from "vuedraggable";

	export default {
		components: {
			vuedraggable
		},
		props: {
			columns: Array
		},
		data() {
			return {
				tableData: []
			};
		},
		methods: {
			init() {
				const data = Object.assign([], this.$props.columns);
				this.tableData = data.map(item => {
					return {
						...item,
						hide: !item.hide
					};
				});
			},
			save() {
				let data = Object.assign([], this.tableData);
				data = data.map(item => {
					return {
						...item,
						hide: !item.hide
					};
				});
				this.$emit("columns-change", data);
			}
		},
		created() {
			this.init();
		}
	};
</script>

<style lang="scss" scoped>
	.table>.table-row {
		font-weight: 600;
	}

	.table-row {
		display: flex;
		padding: 10px;
		border-bottom: 1px solid #eee;
	}

	.table-cell {
		width: 30%;
		height: 35px;
		display: flex;
		align-items: center;

		&:nth-child(1) {
			width: 55px;
		}

		&:nth-child(2) {
			width: 40%;
		}
	}
</style>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值