二次封装element-plus的TableAndPage

745 阅读1分钟

二次封装element-plus的TableAndPage

首先梳理一下要用到那些东西:
1) vue: {
    defineComponent, // 编写ts需要该方法包裹
    openBlock, // 创建一个初始化一个块
    createBlock, // 创建一个块
    renderSlot, // 渲染slot, 他有四个参数:($slot, '插入的名': string, 传入的参数:object, fallback: () => VNodeArrayChildren, onSlotted: Boolean)
    resolveComponent, // 解析组件, 他有俩参数: (组件名, maybeSelfReference: Boolean)
    withDirectives, // 创建指令
    resolveDirective, // 解析已有的指令,他有一个参数:(指令名:string)
    withCtx, // 这个方法我也不是很懂,望大佬解答, 貌似用来记录插入的vnode
    mergeProps, // 这个是用来继承属性的
}


2) element-plus: {
    ElTable, 表格
    ElPagination, // 分页
}
定义一下组件需要的props:
props: {
        /**
         * 组件id
         */
        idx: {
            type: String,
            default: 'diy-1',
            require: true,
        },
        /**
         * 获取数据的接口函数
         */
        ajaxData: {
            type: Function,
            default: ()=> (() => Promise),
            require: true,
        },
        /**
         * Table 的最大高度。合法的值为数字或者单位为 px 的高度。
         */
        maxHeight: {
            type: Number || String,
        },
        /**
         * Table 当前加载的分页
         */
        currentPage: {
            type: Number,
            default: 1,
        },
        /**
         * 是否需要loading
         */
        isLoading: {
          type: Boolean,
          default: false
        },
        /**
         *  获取数据接口的参数
         */
        params: {
            type: Object,
            default: {
                page: 1,
                size: 20
            },
            require: true,
        },
        /**
         * 接口返回数据列表的key
         */
        requsetKey: {
            type: Object,
            default: () => ({
                key1: 'data',
                key2: 'list'
            })
        }
    }
定义一下组件需要的方法以及属性:
setup (props, context) {
        const { ajaxData, params, requsetKey, currentPage, isLoading } = toRefs(props);

        const list = reactive<Array<IOBJ>>([]);
        const total = ref<number>(400);
        const pageSizes = reactive<Array<number>>([1, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]);
        const loading = ref<boolean>(false);
        /*这个方法的递归获取列表*/
        const indexKey = (keys: Array<string>, params: any, index: number = 0): any => {

            if (Array.isArray(params)) return params;

            params = params[requsetKey.value[keys[index]]]
            index++;

            return indexKey(keys, params, index);
        };

        const getList = async (pageNo?: number) => {
            pageNo && (params.value.page = pageNo);
            loading.value = isLoading.value;
            const keys = Reflect.ownKeys(requsetKey.value) as Array<string>;
            let res = await ajaxData.value(params.value);
            const data = indexKey(keys, res)
            list.splice(0);
            list.push(...data);
            total.value = res.data.total;
            loading.value = false;
        }
        onMounted(() => {
            !params.value.page && Object.assign(params.value, {page: 1, size: 20});
        })

        const handleSizeChange = (val: number) => {
            params.value.size = val;
            getList().catch();
        }

        const handleCurrentChange = (val: number) => {
            params.value.page = val;
            getList().catch();
        }

        return {
            handleSizeChange,
            handleCurrentChange,
            total,
            getList,
            pageSizes,
            loading,
            list,
            // id: 'table-'
        }

    }

渲染函数:
let see = 1;
script.__file = 'src/components/TableAndPage/index.ts';
script.install = (App: IOBJ) => {
    App.component(script.name, script);
}

script.render = (ctx: IOBJ, cache: Array<any>, $props: IOBJ, $setup: Function, $data: IOBJ, $options: IOBJ) => {
    ++see;
    const componentElPagination = resolveComponent(ElPagination.name);
    const componentElTable = resolveComponent(ElTable.name);
    const directiveLoading = resolveDirective('loading') as Directive;
    // console.log(ctx.idx, toDisplayString(ctx.idx));
    return(openBlock(), createBlock('div', {
        id: toDisplayString(ctx.idx),
        className: '423423'
    }, [
        createVNode('div', {id: toDisplayString(ctx.idx)}, {
                renderSlot(ctx.$slots, 'default', {
                    list: ctx.list,
                    loading: ctx.loading,
                    maxHeight: ctx.maxHeight
                }),
         ctx.$slots.inline && withDirectives((openBlock(), createBlock(componentElTable, mergeProps(ctx.$attrs,{
                    data: ctx.list,
                    border: true,
                    maxHeight: ctx.maxHeight,
                }), {
                    inline: withCtx(() => [
                        renderSlot(ctx.$slots, 'inline')
                    ], undefined)
                }, 8/* PROPS */, ['data', 'border', 'maxHeight'])), [
                    [directiveLoading, ctx.loading]
                ]),
        }, 512 /*NEED_PATCH*/),
        createVNode(componentElPagination, {
            onSizeChange: ctx.handleSizeChange,
            // currentPage: ctx.currentPage,
            onCurrentChange: ctx.handleCurrentChange,
            // 'onUpdate:currentPage': cache[0] || (cache[0] =  ($event: number) => ctx.$emit('update:currentPage', $event)),
            pageSizes: ctx.pageSizes,
            pageSize: ctx.params.size,
            layout: "total, sizes, prev, pager, next, jumper",
            total: ctx.total,
        }, null, 8, [
            'onSizeChange',
            // 'currentPage',
            'onCurrentChange',
            // 'onUpdate:currentPage',
            'pageSizes',
            'pageSize',
            'total'
        ])
    ], 512 /* NEED_PATCH */))
}
export default script;
使用
import {
    defineComponent,
    ref,
    createBlock,
    openBlock,
    createVNode,
    Transition,
    reactive,
    Fragment,
    renderList,
    withDirectives,
    vModelText,
    resolveComponent,
    withCtx,
    toDisplayString,
    onMounted,
    resolveDirective,
    getCurrentInstance,
    Directive, createTextVNode,
} from 'vue';

import {ElInput, ElButton, ElTable, ElTableColumn, ElRadioGroup, ElRadioButton} from 'element-plus';

import TableAndPage from '@/components/TableAndPage/index';
import { getLike } from '@/assets/api/song';
export default defineComponent({
    components: {
        'table-and-page': TableAndPage,
    },
    setup () {
        const current = ref(6);
        const TableAndPageRef = ref<IOBJ | null>(null);
        const params = reactive<IOBJ>({})



        onMounted(() => {
            TableAndPageRef.value && TableAndPageRef.value.getList(1)
        })
        const componentTableAndPage = resolveComponent('table-and-page');
        const directiveLoading = resolveDirective('loading') as Directive;

        return (ctx: any, cache: any) => {
           
            return (openBlock(), createBlock('div', {
                id: 'my-favorites',
                class: 'favorites',
            }, [
                createVNode(componentTableAndPage, {
                        ajaxData: getLike,
                        params: params,
                        id: 'table',
                        ref: TableAndPageRef,
                        isLoading: true,
                        // currentPage: current.value,
                                // 'onUpdate:currentPage': cache[3] || (cache[3] = ($event: number) => (current.value = $event)),
                    },
                    {
                        default: withCtx(({list, loading, maxHeight}: IOBJ) => [
                            withDirectives(createVNode(componentElTable, {
                                data: list,
                                maxHeight: maxHeight,
                                onLoading: loading,
                            }, [
                                createVNode(componentElTableColumn, {
                                    prop:'song_name',
                                    label: '音乐标题'
                                }),
                                createVNode(componentElTableColumn, {
                                    prop: 'singer_name',
                                    label: '歌手'
                                })
                            ], 8, ['data', 'maxHeight']), [
                                [directiveLoading, loading]
                            ]),

                        ], undefined),
                        _: 1,
                    }, 520 /* PROPS, NEED_PATCH */, ['ajaxData', 'params', 'onUpdate:currentPage', 'currentPage', 'isLoading'])

            ], HOISTED));
        }
    },
})


有的东西没讲那么详细 第一篇文章有 大功告成 哇哈哈哈 明天见