Element UI 表格 el-table 二次封装

Element UI 表格进行二次封装

Tips: 文章末尾有完整封装代码

一、继承 element 表格属性

需要将element提供的表格属性使用props传入组件中

props: {
	// 表头数据 { slot: 'xxx', header: 'xxx' }[]
	// slot:自定义列的slot-name;header:自定义表头的slot-name
	columns: Array,
	// 表格加载动画
	loading: Boolean,
	// ...其余属性同 ElementUI 表格 Attributes 直接传入即可
}

二、配置 element 表格的表头

  1. 使用 props 传入的表头数据遍历得到表格的表头。
<el-table-column v-for="item in columns" :key="item.prop" v-bind="item"></el-table-column>
<!-- or -->
<el-table-column
    v-for="item in columns" :key="item.prop"
    :prop="item.prop"
    :label="item.label"
    :align="item.align || 'left'"
    :header-align="item.headerAlign || 'left'"
    :show-overflow-tooltip="item.tooltip || false"
    :min-width="item.minWidth"
    :width="item.width"
    :fixed="item.fixed"
    :class-name="item.columnClass"
    :label-class-name="item.labelClassName"
/>
<!-- or -->
<el-table-column v-for="item in columns" :key="item.prop" v-bind="item">
	<template v-if="item.header" #header="scope">
		<slot :name="item.header" v-bind="scope"></slot>
	</template>
	<template v-if="item.slot" #default="scope">
		<slot :name="item.slot" v-bind="scope"></slot>
	</template>
</el-table-column>
  1. 有些列的数据需要自定义内容,例如:操作列、不同样式的数据展示等。

方式一
需要自定义内容的列可以使用 <slot></slot> 传入自定义内容;这里就不能直接在 <el-table-column></el-table-column> 上使用 v-for 来遍历了,需要使用 <template></template> 来进行 v-for 的循环遍历,此时需要注意的是 v-for 需要定义一个 v-bind:key 但是不能直接将 key 赋给 <template ></template > 但是可以将 key 赋给其他组件 例如 <el-table-column :key="index"></el-table-column>

<!-- 方式一 -->
<template v-for="item in columns">
    <!-- 操作列/自定义列 -->
    <slot v-if="item.slot" :name="item.slot"></slot>
    <el-table-column :key="item.prop" v-bind="item"></el-table-column>
    <!-- or
    <el-table-column
        v-else
        :key="item.prop"
        :prop="item.prop"
        :label="item.label"
        :align="item.align || 'left'"
        :header-align="item.headerAlign || 'left'"
        :show-overflow-tooltip="item.tooltip || false"
        :min-width="item.minWidth"
        :width="item.width"
        :fixed="item.fixed"
        :class-name="item.columnClass"
        :label-class-name="item.labelClassName"
    ></el-table-column>
	-->
</template>

方式二
在父组件中使用时不用再写 <el-table-column></el-table-column> 标签,直接在 table 中写对应的 slot 内容即可

<el-table-column v-for="item in columns" :key="item.prop" v-bind="item">
	<!-- 自定义表头的内容 -->
	<template v-if="item.header" #header="scope">
		<slot :name="item.header" v-bind="scope"></slot>
	</template>
	<!-- 自定义列的内容 -->
	<template v-if="item.slot" #default="scope">
		<slot :name="item.slot" v-bind="scope"></slot>
	</template>
</el-table-column>

例如 父组件

<p-table ref="package-table" :columns="columns" :data="data">
	<template #name="{ row }">
		<span>{{ row.name }}</span>
	</template>
</p-table>

<script>
	export default {
		data: () {
			return {
				data: [
					{
						name: '张三',
					},
				],
				columns: [
					{
						props: 'name',
						label: '姓名',
						width: '120px',
						slot: 'name',
					},
				],
			};
		},
	}
</script>

三、element 表格事件

  1. Table Events 如果需要使用一些表格返回的事件,可以使用 this.$emit() 传递给父组件
    也可以直接使用 v-on="$attrs" 绑定外部传入的事件

例如@cell-click 当某个单元格被点击时会触发该事件 row, column, cell, event

// @cell-click="cellClick"
methods: {
	cellClick(row, column, cell, event) {
		this.$emit('cell-click', {row, column, cell, event})
	}
}
  1. Table Methods 如果需要使用一些表格的方法,可以在父组件使用 this.$refs['父组件中子组件的ref'].$refs['子组件table的ref'].方法名 调用

例如clearSort() 用于清空排序条件,数据会恢复成未排序的状态

<!-- 父组件 -->
<template>
	<p-table ref="package-table" :columns="columns" :data="data">
		<template #name="{ row }">
			<span>{{ row.name }}</span>
		</template>
	</p-table>
</template>

<script>
	export default {
		data: () {
			return {
				data: [
					{
						name: '张三',
						age: 24,
					},
					{
						name: '李四',
						age: 35,
					},
				],
				columns: [
					{
						props: 'name',
						label: '姓名',
						width: '120px',
						slot: 'name',
					},
					{
						props: 'age',
						label: '年龄',
					},
				],
			};
		},
		methods: {
			// 调用表格方法
			clearSort() {
				this.$refs['package-table'].$refs.tableRef.clearSort()
			}
		}
	}
</script>
<!-- 子组件 -->
<template>
    <el-table ref="tableRef" v-loading="loading" v-bind="$attrs" v-on="$attrs"></el-table>
</template>

至此,对 element 表格的二次封装就已经大功告成了!

完整代码

<template>
	<!-- @cell-click="cellClick" -->
    <el-table
        ref="tableRef"
        v-loading="loading"
        v-bind="$attrs"
        v-on="$attrs"
    >
        <template v-for="item in columns">
            <!-- 自定义table-column -->
            <slot v-if="item.slot" :name="item.slot"></slot>
            <el-table-column :key="item.prop" v-bind="item" />
            <!--
				<el-table-column
	                v-else
	                :key="item.prop"
	                :prop="item.prop"
	                :label="item.label"
	                :align="item.align || 'left'"
	                :header-align="item.headerAlign || 'left'"
	                :show-overflow-tooltip="item.tooltip || false"
	                :min-width="item.minWidth"
	                :width="item.width"
	                :fixed="item.fixed"
	                :class-name="item.columnClass"
	                :label-class-name="item.labelClassName"
	            />
			-->
        </template>
        <!-- 插入至表格最后一行之后的内容-->
        <template #append v-if="$slots.append">
        	<slot name="append" />
        </template>
        <!-- 空数据时显示的内容 -->
        <template #empty v-if="$slots.empty">
          <slot name="empty" />
        </template>
    </el-table>
</template>

<script>
export default {
    name: 'package-table',
    props: {
    	// 表头数据 Table-column Attributes
		// { slot: 'xxx', header: 'xxx' }[]
		// slot:自定义列的slot-name;header:自定义表头的slot-name
        columns: Array,
        // 表格加载动画
        loading: Boolean,
        // ...其余属性同 ElementUI 表格 Attributes 直接传入即可
    },
    // methods: {
    //	 // 点击单元格
	//	 cellClick(row, column, cell, event) {
	//	 	 this.$emit('cell-click', {row, column, cell, event})
	//	 }
	// },
}
</script>

or

<template>
    <el-table
        ref="tableRef"
        v-loading="loading"
        v-bind="$attrs"
        v-on="$attrs"
    >
		<el-table-column v-for="item in columns" :key="item.prop" v-bind="item">
			<!-- 自定义表头的内容 -->
			<template v-if="item.header" #header="scope">
				<slot :name="item.header" v-bind="scope"></slot>
			</template>
			<!-- 自定义列的内容 -->
			<template v-if="item.slot" #default="scope">
				<slot :name="item.slot" v-bind="scope"></slot>
			</template>
		</el-table-column>
		
        <!-- 插入至表格最后一行之后的内容-->
        <template #append v-if="$slots.append">
        	<slot name="append" />
        </template>
        <!-- 空数据时显示的内容 -->
        <template #empty v-if="$slots.empty">
          <slot name="empty" />
        </template>
    </el-table>
</template>

<script>
export default {
    name: 'package-table',
    props: {
    	// 表头数据 Table-column Attributes
		// { slot: 'xxx', header: 'xxx' }[]
		// slot:自定义列的slot-name;header:自定义表头的slot-name
        columns: Array,
        // 表格加载动画
        loading: Boolean,
        // ...其余属性同 ElementUI 表格 Attributes 直接传入即可
    },
}
</script>

Ending…
ding…
ng…

.

ElementUItable 组件提供了非常丰富的功能和接口,但是在实际项目中,我们经常需要对其进行二次封装,以满足自己的业务需求。下面是一个简单的 ElementUI table二次封装示例: ```vue <template> <el-table :data="tableData" :height="height" :max-height="maxHeight" :stripe="stripe" :border="border" :fit="fit" :show-header="showHeader" :highlight-current-row="highlightCurrentRow" :row-class-name="rowClassName" :row-style="rowStyle" :cell-class-name="cellClassName" :cell-style="cellStyle" :header-row-class-name="headerRowClassName" :header-row-style="headerRowStyle" :header-cell-class-name="headerCellClassName" :header-cell-style="headerCellStyle" :row-key="rowKey" @select="handleSelect" @select-all="handleSelectAll" @selection-change="handleSelectionChange" @cell-mouse-enter="handleCellMouseEnter" @cell-mouse-leave="handleCellMouseLeave" @cell-click="handleCellClick" @cell-dblclick="handleCellDblClick" @row-click="handleRowClick" @row-contextmenu="handleRowContextMenu" @row-dblclick="handleRowDblClick" @header-click="handleHeaderClick" @header-contextmenu="handleHeaderContextMenu" @sort-change="handleSortChange" @filter-change="handleFilterChange" > <slot></slot> </el-table> </template> <script> export default { name: "MyTable", props: { tableData: { type: Array, default: () => [] }, height: { type: [Number, String], default: "" }, maxHeight: { type: [Number, String], default: "" }, stripe: { type: Boolean, default: true }, border: { type: Boolean, default: true }, fit: { type: Boolean, default: true }, showHeader: { type: Boolean, default: true }, highlightCurrentRow: { type: Boolean, default: true }, rowClassName: { type: Function, default: () => undefined }, rowStyle: { type: Function, default: () => undefined }, cellClassName: { type: Function, default: () => undefined }, cellStyle: { type: Function, default: () => undefined }, headerRowClassName: { type: Function, default: () => undefined }, headerRowStyle: { type: Function, default: () => undefined }, headerCellClassName: { type: Function, default: () => undefined }, headerCellStyle: { type: Function, default: () => undefined }, rowKey: { type: [String, Function], default: "" } }, methods: { handleSelect(selection, row) { this.$emit("select", selection, row); }, handleSelectAll(selection) { this.$emit("select-all", selection); }, handleSelectionChange(selection) { this.$emit("selection-change", selection); }, handleCellMouseEnter(row, column, cell, event) { this.$emit("cell-mouse-enter", row, column, cell, event); }, handleCellMouseLeave(row, column, cell, event) { this.$emit("cell-mouse-leave", row, column, cell, event); }, handleCellClick(row, column, cell, event) { this.$emit("cell-click", row, column, cell, event); }, handleCellDblClick(row, column, cell, event) { this.$emit("cell-dblclick", row, column, cell, event); }, handleRowClick(row, event, column) { this.$emit("row-click", row, event, column); }, handleRowContextMenu(row, event) { this.$emit("row-contextmenu", row, event); }, handleRowDblClick(row, event) { this.$emit("row-dblclick", row, event); }, handleHeaderClick(column, event) { this.$emit("header-click", column, event); }, handleHeaderContextMenu(column, event) { this.$emit("header-contextmenu", column, event); }, handleSortChange({ column, prop, order }) { this.$emit("sort-change", { column, prop, order }); }, handleFilterChange(filters) { this.$emit("filter-change", filters); } } }; </script> ``` 这里我们定义了一个名为 `MyTable` 的组件,并将其 props 与 ElementUI table 组件的 props 一一对应。在组件的模板中,我们使用了 `<slot></slot>`,表示组件的插槽,这样可以让用户在使用组件时自定义表格的列和内容。在组件的方法中,我们将 ElementUI table 的事件通过 `$emit` 的方式向上传递,这样可以使得组件的使用更加灵活。 使用这个组件时,我们只需要在父组件中引入 `MyTable` 组件,并将需要的 props 和插槽传入即可: ```vue <template> <my-table :table-data="tableData" :stripe="false" :highlight-current-row="false" @row-click="handleRowClick" > <el-table-column label="姓名" prop="name"></el-table-column> <el-table-column label="年龄" prop="age"></el-table-column> <el-table-column label="地址" prop="address"></el-table-column> </my-table> </template> <script> import MyTable from "@/components/MyTable"; export default { name: "MyPage", components: { MyTable }, data() { return { tableData: [ { name: "张三", age: 18, address: "北京市" }, { name: "李四", age: 20, address: "上海市" }, { name: "王五", age: 22, address: "广州市" } ] }; }, methods: { handleRowClick(row) { console.log(row); } } }; </script> ``` 这样,我们就完成了一个简单的 ElementUI table二次封装,并且可以在父组件中灵活使用。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DevilAngelia

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值