vue3 使用 hooks 封装 Element-plus table 支持查询参数,自动分页,自动调用接口,CV即用,欢迎指导!!

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.效果

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值