1.hooks 封装
interface ApiConfig {
api: (...args: any[]) => Promise<any>;
params?: Object;
pageSize: string;
pageNumber: string;
formatResults: (data: any) => [any, number];
}
export const useTable = (apiConfig: ApiConfig, options?: { defaultPageSize?: number; isPagination: boolean }) => {
const defaultPageSize = options?.defaultPageSize ?? 10;
const { api, pageSize: sizePropName, pageNumber: numberPropName, formatResults } = apiConfig;
const { pageSize, pageNumber, total, setTotal, changeNumberAndSize } = usePagination(() => getTableData(), {
defaultPageSize
});
const loading = ref(true);
const tableData = ref<any>([]);
const getTableData = async () => {
try {
loading.value = true;
let apiParams: any = {};
if (options?.isPagination) {
apiParams = {
[sizePropName]: pageSize.value,
[numberPropName]: pageNumber.value
};
}
if (apiConfig.params) {
apiParams = {
...apiConfig.params,
...apiParams
};
}
const res = await api(apiParams);
const [data, totalCount] = formatResults ? formatResults(res) : [res, 0];
setTotal(totalCount);
tableData.value = data;
loading.value = false;
} catch (err) {
loading.value = false;
console.error('表格数据请求出错啦!!!', err);
}
};
return { tableData, loading, pageSize, pageNumber, total, changeNumberAndSize, getTableData };
};
interface PaginationOptions {
defaultPageSize: number;
}
export const usePagination = (callback: () => void, paginationOptions: PaginationOptions) => {
const { defaultPageSize } = paginationOptions;
const pagination = reactive({
pageSize: defaultPageSize || 10,
pageNumber: 1,
total: 0,
change: (pageNumber: number, pageSize: number) => {
pagination.pageNumber = pageNumber;
pagination.pageSize = pageSize;
callback();
}
});
const setTotal = (total: number) => {
pagination.total = total;
};
const changeNumberAndSize = pagination.change;
const { pageSize, pageNumber, total } = toRefs(pagination);
return { pageSize, pageNumber, total, setTotal, changeNumberAndSize };
};
2.封装 table
<template>
<el-table
:data="tableData"
style="width: 100%"
v-loading="loading"
element-loading-text="Loading..."
element-loading-background="rgba(122, 122, 122, 0.8)"
:border="tableConfig.border"
:stripe="tableConfig.stripe"
:fit="tableConfig.fit"
:show-header="tableConfig['show-header']"
:size="tableConfig.size"
:height="tableConfig.height"
:max-height="tableConfig['max-height']"
:header-cell-style="tableConfig.headerCellStyle"
:row-style="tableConfig.rowStyle"
tooltip-effect="dark"
:tooltip-options="{
effect: 'dark',
placement: 'top',
showArrow: true
}"
>
<el-table-column type="index" width="60" label="序号" />
<el-table-column
v-for="{ label, prop, width, slot, fixed, sortable } in tableList"
:key="prop"
:prop="prop"
:label="label"
:width="width"
:fixed="fixed"
:sortable="sortable"
:show-overflow-tooltip="true"
>
<template v-if="slot" #default="scope">
<slot :name="prop" v-bind="scope"></slot>
</template>
<template v-else #default="scope">
<template v-if="Array.isArray(scope.row[prop])">
<div class="array_p" v-for="item in scope.row[prop]" :key="item">
{{ item }}
</div>
</template>
<template v-else>
{{ scope.row[prop] }}
</template>
</template>
</el-table-column>
<template #empty>
<NoData class="empty" v-show="!loading && !tableData.length"></NoData>
</template>
</el-table>
<el-pagination
v-if="paginationConfig.isPagination"
v-model:current-page="pageNumber"
v-model:page-size="pageSize"
:page-sizes="paginationConfig['page-sizes']"
:small="paginationConfig.small"
:disabled="paginationConfig.disabled"
:background="paginationConfig.background"
:layout="paginationConfig.layout"
:total="total"
@change="changeNumberAndSize"
/>
</template>
<script setup lang="ts">
import { useTable } from 'hooks/useTable';
import {
Table,
Pagination,
TableListItem,
TableApi,
SpanMethodProps
} from 'types/components/Table';
/**
* element table + Pagination 二次封装
*/
const tableConfigObj = {
border: true,
stripe: false,
fit: true,
'show-header': true,
size: 'default', //large / default /small
height: '100%',
headerCellStyle(data: { row: any; column: any; rowIndex: number; columnIndex: number }) {
return {
padding: '4px', // 设置Table表头单元内边距
backgroundColor: '#e7f0ff', // 设置Table表头背景颜色
borderColor: '#ccc', // 设置Table表头边框颜色
color: '#000', // 设置Table表头文字颜色
fontSize: '16px', // 设置Table表头文字大小
textAlign: 'center', // 设置Table表头文字对齐方式
fontWeight: 'normal' // 设置Table表头文字粗细
};
},
rowStyle({ row, rowIndex }: { row: any; rowIndex: number }) {
console.log(row, rowIndex);
if (rowIndex % 2 == 0) {
return {
backgroundColor: 'rgba(255, 100, 100, 0.3)'
};
}
}
};
const paginationConfigObj = {
isPagination: true,
layout: 'total, sizes, prev, pager, next, jumper', //total, sizes, prev, pager, next, jumper
'page-sizes': [10, 20, 30, 40],
small: false,
disabled: false,
background: true
};
const props = defineProps({
tableOptions: {
type: Object as () => Table,
default: () => ({})
},
paginationOptions: {
type: Object as () => Pagination
},
tableList: {
type: Array<TableListItem>,
required: true,
default: () => [
// {
// label: "名字",
// prop: "name",
// width: "120",
// },
]
},
tableApi: {
type: Object as () => TableApi,
required: true,
default: () => ({
// api: getTableData1,
// params: { name: 'afsv' },
// pageSize: 'pageSize',
// pageNumber: 'pageNumber',
// formatResults: (res: any) => {
// const { results, totalSum } = res;
// return [results, totalSum];
// }
})
}
});
const tableConfig = computed(() => Object.assign({}, tableConfigObj, props.tableOptions));
const paginationConfig = computed(() =>
Object.assign({}, paginationConfigObj, props.paginationOptions)
);
const { tableData, loading, pageSize, pageNumber, total, changeNumberAndSize, getTableData } =
useTable(props.tableApi, { isPagination: paginationConfig.value.isPagination });
watch(
() => props.tableApi.params,
() => {
getTableData();
},
{ deep: true, immediate: true }
);
defineExpose({
getTableData
});
</script>
<style lang="scss" scoped>
.el-pagination {
display: flex;
justify-content: center;
margin-top: 20px;
}
.array_p {
overflow: auto;
}
.array_p::-webkit-scrollbar {
display: none;
}
</style>
3.使用
<Table ref="childRef" :tableList="tableList" :tableApi="tableApi">
<template #id="scope">
<div
:style="{
display: 'flex',
justifyContent: 'space-between'
}"
>
<div @click="() => click(scope.row)">删除</div>
<div @click="() => click(scope.row)">详情</div>
<div @click="() => click(scope.row)">编辑</div>
</div>
</template>
</Table>
const childRef = ref(null);
const click = (val: any) => {
console.log(val);
};
const tableApi = reactive({
api: getTableData1,
params: { name: 'afsv' },
pageSize: 'pageSize',
pageNumber: 'pageNumber',
formatResults: (res: any) => {
const { results, totalSum } = res;
return [results, totalSum];
}
});
setTimeout(() => {
tableApi.params = { name: '12345' };
}, 5000);
const tableList = [
{
label: '时间',
prop: 'date',
sortable: true
},
{
label: '名字',
prop: 'name',
width: '120'
},
{
label: '详情',
prop: 'address'
},
{
label: '操作',
prop: 'id',
slot: true,
width: '120'
}
];
4.效果