Vue3+TS项目封装一个公共的el-table组件二次封装
前言
支持动态传入列,列内容可以指定插槽,指定格式化显示
样式没太写,主要分享基础功能封装
效果
Table组件代码BaseTable.vue
<template>
<el-table :data="data" border>
<template v-for="col in columns" :key="col.prop">
<el-table-column :prop="col.prop" :label="col.label" :width="col.width" show-overflow-tooltip>
<template #default="{ row }">
<slot v-if="col.slot" :name="col.slot"></slot>
<!-- 因为这个内容不是通过表格的prop直接绑定的,所以表格自带的溢出省略号失效,自己写下 -->
<div v-else class="text-overflow">{{ getFormatter(col, row[col.prop]) }}</div>
</template>
</el-table-column>
</template>
</el-table>
<br>
<template v-if="isShowPage">
<el-pagination v-model:currentPage="currentPage1" v-model:page-size="pageSize1" :page-sizes="[10, 20, 30, 40]"
background layout="total, sizes, prev, pager, next, jumper" :total="totalSize" @size-change="sizeChange"
@current-change="currentChange" />
</template>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue';
export interface BaseTableConfig {
data: any[];
columns: TableColumn[];
current?: number;
pageSize?: number;
totalSize?: number;
[key: string]: any;
}
export interface TableColumn {
prop?: string;
label: string;
slot?: string;
width?: number;
formatter?: Function;
[key: string]: any;
}
const emit = defineEmits(['update:pageSize', 'update:currentPage', 'pageChange'])
const props = defineProps({
data: {
type: Array,
default: () => ([])
},
columns: {
type: Array<any>,
default: () => ([])
},
currentPage: {
type: Number,
default: 1,
},
pageSize: {
type: Number,
default: 10,
},
totalSize: {
type: Number,
default: 0,
},
isShowPage: {
type: Boolean,
default: true,
}
});
const currentPage1 = ref(props.currentPage);
const pageSize1 = ref(props.pageSize);
const getFormatter = (col: any, value: any) => {
if (col.formatter) {
return col.formatter(value);
}
return value;
}
const sizeChange = (val: number) => {
emit('update:pageSize', val);
emit('pageChange');
}
const currentChange = (val: number) => {
emit('update:currentPage', val);
emit('pageChange');
}
</script>
<style scoped>
.text-overflow {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
</style>
页面中使用组件
<template>
<div>总条数:{{ tbConfig.totalSize }};当前页:{{ tbConfig.current }};每页条数:{{ tbConfig.pageSize }}</div>
<BaseTable :data="tbConfig.data" :columns="tbConfig.columns" v-model:currentPage="tbConfig.current"
v-model:pageSize="tbConfig.pageSize" :totalSize="tbConfig.totalSize" @pageChange="pageClick">
<template #avatar="{ row }">
这一列用插槽自定义内容{{ row?.avatar }}
</template>
<template #op>
<el-button type="danger">删除</el-button>
</template>
</BaseTable>
</template>
<script lang="ts" setup>
import { reactive } from 'vue';
import { BaseTableConfig, TableColumn } from './BaseTable.vue';
import BaseTable from './BaseTable.vue';
const tbConfig: BaseTableConfig = reactive({
data: [
{ id: 1, name: 'Ahsh', avatar: 'img1.png', ifKey: true },
{ id: 2, name: 'Rjjds', avatar: 'img2.png', ifKey: false },
{ id: 3, name: 'Ukkd特别长长长长长长长长长长的名字', avatar: 'img3.png', ifKey: true },
],
columns: <TableColumn[]>[
{ prop: 'id', label: '序号', width: 100 },
{ prop: 'name', label: '名称', width: 200 },
{ prop: 'avatar', label: '图标', slot: 'avatar', width: 200 },
{ prop: 'ifKey', label: '是否开放', formatter: formatBoolean },
{ label: '操作', slot: 'op' },
],
current: 1,
pageSize: 10,
totalSize: 0,
});
function formatBoolean(val: Boolean) {
return val ? '是' : '否';
}
function pageClick() {
// TODO监听到当前页或者每页条数变化,重新查询列表
console.log('get-data');
}
</script>
<style scoped></style>