基于ElementPlus的table组件封装

前言

我们在使用UI库编写页面的时候,特别是账务系统,需要用到表格的情况会比较多,如果我们每次都是复制一遍UI库中的demo然后进行调整,这样造成的结果是多次引入 Table 组件,而且从前端开发规范来讲,不符合组件化的初衷。因此我们将 Table 组件进行二次封装,无疑是最好的选择。二次封装 Table 组件就是为了增强组件的可复用性、可维护性和功能性。

二次封装的优势
  1. 统一风格和功能
    • 样式一致性:项目中可能有多个地方使用表格,二次封装可以确保所有表格在样式和功能上保持一致。
  2. 简化使用
    • 简化 API:通过封装,可以提供更简单、更直观的 API,减少开发者在使用时需要考虑的细节。例如,可以通过 props 传递配置选项,而不必每次都重复编写配置。
    • 封装复杂逻辑:将复杂的逻辑(例如数据处理、列渲染)封装到一个组件中,调用方只需使用这个封装的组件即可,降低了使用难度。
  3. 增强功能
    • 插槽:通过插槽,可以灵活地扩展表格的功能,例如自定义列内容、操作按钮等,提升组件的灵活性。
    • 事件处理:可以统一处理表格中的各种事件,如行点击、行选中等,提供更一致的事件响应方式。
  4. 提高可维护性
    • 集中管理:将表格的所有相关逻辑集中到一个地方,使得后续的维护和修改更加简单。如果需要更改某个功能,只需在封装的组件中进行修改,而不必在每个使用表格的地方重复修改。
    • 易于调试:封装后的组件可以更容易进行单元测试和调试,确保表格的各项功能在不同场景下都能正常工作。
  5. 提高开发效率
    • 复用性:封装后的组件可以在不同的项目中复用,节省开发时间。通过封装常用的表格功能,可以减少重复劳动。
    • 快速迭代:通过提供易于使用的组件,团队成员可以快速上手并使用,而不必深入了解底层实现。

我使用的技术栈是Vue3+Ts+Element Plus,所以此次table组件的二次封装也是基于Element Plus的,其中Element Plus版本选的是2.8.0

前提条件

默认大家已经能够正确地创建Vue3+Ts的前端工程,Element Plus的安装可以参考https://element-plus.org/zh-CN/guide/installation.html,还需要大家在提前注册Element Plus所有的图标。代码如下:

// main.ts

import * as ElementPlusIconsVue from '@element-plus/icons-vue';

// 注册elementPlus所有的图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
   
   
    app.component(key, component)
}
封装代码源码
// c-table/components/table-column-item/index.vue

<template>
	<el-table-column
		v-if="!column.children && column.type !== 'selection' && column.type !== 'expand'"
		:prop="column.prop"
		:label="column.label"
		:width="column.width"
		:show-overflow-tooltip="column.showOverflowTooltip"
		:fixed="column.fixed"
		:min-width="column.minWidth"
		:align="column.align"
		:type="column.type"
		:resizable="column.resizable"
		:sortable="column.sortable"
		:selectable="column.selectable"
		:column-key="column.columnKey"
		:filters="column.filters"
		:filter-method="column.filterMethod"
		:sort-method="column.sortMethod"
        :sort-by="column.sortBy"
        :sort-orders="column.sortOrders"
        :header-align="column.headerAlign"
        :class-name="column.className"
        :label-class-name="column.labelClassName"
        :reserve-selection="column.reserveSelection"
        :filter-placement="column.filterPlacement"
        :filter-class-name="column.filterClassName"
        :filter-multiple="column.filterMultiple"
        :filter-value="column.filterValue"
	>
		<template #default="{ row, $index }">
			<template v-if="column.formatter">
				<template v-if="isStringFormatter(row, $index)">
					{
  
  {
						column.formatter(row, column, row[column.prop], $index)
					}}
				</template>
				<template v-else>
					<component
						:is="
							column.formatter(
								row,
								column,
								row[column.prop],
								$index
							)
						"
					/>
				</template>
			</template>
			<template v-if="column.index && !column.formatter">
				{
  
  { column.index($index) }}
			</template>
			<component
				:is="column.slots.default"
				:row="row"
				:index="$index"
				v-if="column.slots && column.slots.default"
			/>
		</template>
		<template #header="scope" v-if="column.slots && column.slots.header">
			<component
				:is="column.slots.header"
				:row="scope.row"
				:index="scope.$index"
			/>
		</template>
	</el-table-column>
    <!-- 多级表头 -->
	<el-table-column
		v-if="column.children && column.type !== 'expand'"
		:prop="column.prop"
		:label="column.label"
		:align="column.align"
		:type="column.type"
		:resizable="column.resizable"
	>
		<template v-for="child in column.children" :key="child.prop">
			<table-column-item :column="child" />
		</template>
	</el-table-column>
    <!-- 多选 -->
	<el-table-column
		v-if="column.type == 'selection'"
		type="selection"
		:width="column.width"
		:selectable="column.selectable"
	/>
	<!-- 展开行 -->
	<el-table-column v-if="column.type == 'expand'" type="expand">
		<template #default="{ row, $index }">
			<component
				:is="column.slots.default"
                :row="row"
				:index="$index"
			/>
		</template>
	</el-table-column>
</template>

<script lang="ts">
import { PropType } from "vue";
import { ColumnItem } from "../../../../type";
import { ElTable, ElTableColumn } from "element-plus";

export default {
	name: "TableColumnItem",
	props: {
		column: {
			type: Object as PropType<ColumnItem>,
			default: {},
		},
	},
	components: {
		ElTableColumn,
	},
	setup(props, context) {
		const isStringFormatter = (row: any, index: number): boolean => {
			const formattedValue = props.column.formatter(
				row,
				props.column,
				row[props.column.prop],
				index
			);
			return typeof formattedValue === "string";
		};
		retur
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值