使用vue3二次封装Element-plus过程

2,250 阅读2分钟

萌新启航

之前在其他大佬的博客看到高性能组件所以自己也想写把之封装的给改一下
正好顺变把项目技术给更新一下。。。

应为不是很懂所以先封装个简单的confirm框:


    interface IOBJ {
        [key: string]: any;
    };
    /**
     * 组件接收的参数
     */
    interface IMConfirm {
    showCancel?: boolean;
    cancelText?: string;
    confirmText?: string;
    tipsText?: string;
    title?: string;
    }
    
    /*这里组件实例*/
    const script = defineComponent({
    name: 'confirm',
    props: {
        showCancel: {
            default: true,
            type: Boolean,
        },
        cancelText: {
            default: '取消',
            type: String,
        },
        confirmText: {
            default: '确认',
            type: String,
        },
        tipsText: {
            default: '是否永久删除,此操作不可恢复',
            type: String,
        },
        title: {
            default: '提示',
            type: String,
        }
    },
    setup () {
        // const { emit } = context;
        const visible = ref(true);
        const close = () => {
            return new Promise(((resolve, reject) => {
                visible.value = false;
            }))
        };
        const open = () => {
            visible.value = true;
        }
        return {
            close,
            open,
            visible,
        }
    }
})
    

然后就要开始写渲染函数了函数:

    /**
    *首先考虑的是创建vnode还有,
    *取消按钮这个是不确定的所以需要用到vue的指令然后看了一下文档需要用到这几个函数:
    *createVNode():创建一个vnode,
    一共有五个参数分别是(type: string | vnode'标签名', props: 组件属性 object | null, children: 子元素 array | object | null, PatchFlargs: 后边说 number,
    dynamicProps: 这个是当PatchFlags === 8的时候要填的)。
    *(openBlock(),createBlock()):这俩方法是初始化一个模块和createVNode是差不多的。
    *withDirectives:指令需要的方法有俩个参数(vnode, directive:Array<Array: 四个参数分别是:指令、值、参数、修饰符>)
    */
function render(_ctx: any, _cache: Array, $props: IOBJ, $setup: Function, $data: Function, $options: IOBJ) {
    return(
        openBlock(), createBlock('div', {
            id: _ctx.id,
            class: [
                'bg-f',
                'confirm-box'
            ],
        },
            {
                default: withCtx(() => [
                    withDirectives(createVNode('div',null, [
                            (openBlock(), createBlock('div', {
                                class: 'confirm-top'
                            },  [
                                createVNode('div', {
                                    class: [
                                        'confirm-title'
                                    ],
                                }, [
                                    createVNode('p', {
                                        class: [

                                        ]
                                    }, _ctx.title, PatchFlags.TEXT /* TEXT */)
                                ]),
                                createVNode('div', {
                                    class: [
                                        'confirm-content'
                                    ]
                                }, [
                                    createVNode('p', {
                                        class: [
                                            'confirm-msg',
                                            'tips-title'
                                        ]
                                    }, _ctx.tipsText, PatchFlags.TEXT /* TEXT */)
                                ]),
                            ])),

                            createCommentVNode('按钮', true),
                            (openBlock(), createBlock('div', {
                                class: ['confirm-func-box', 'flex-box', 't-a-c'],
                            }, [
                                _ctx.showCancel && createVNode('div', {
                                    class: [
                                        'flex-1',
                                        'cancel-func',
                                    ],
                                    onClick: _ctx.close
                                }, _ctx.cancelText, PatchFlags.TEXT /* TEXT */),
                                createVNode('div', {
                                    class: [
                                        'flex-1',
                                        'confirm-func',
                                        'main-color'
                                    ],
                                    onClick: _ctx.close
                                }, _ctx.confirmText, PatchFlags.TEXT /* TEXT */)
                            ])),
                        ],  PatchFlags.CLASS /* CLASS */),
                    [
                        [vShow, _ctx.visible]
                    ])
                ])
            },
        )
    )
}

script.render = render;
let seed = 0;
/*这里就不说了*/
const confirm = (opts?: IMConfirm) => {
    seed++
    const id = 'confirm' + seed;
    const options = Object.assign({id}, opts)
    const container = document.createElement('div');
    const vm = createVNode(script, options, null);
    vm.props.onDestroy = () => {
        vue.render(null, container);
    };
    vue.render(vm, container);
    const el = container.firstElementChild;
    document.body.appendChild(el as Element);
}

export {confirm}

接下来说说patchFlags

enum PatchFlags {
    // 动态文字内容
    TEXT = 1,
    // 动态 class
    CLASS = 2,
    // 动态样式
    STYLE = 4,
    // 动态 props
    PROPS = 8,
    // 有动态的key,也就是说props对象的key不是确定的
    FULL_PROPS = 16,
    // 合并事件
    HYDRATE_EVENTS = 32,
    // children 顺序确定的 fragment
    STABLE_FRAGMENT = 64,
    // children中有带有key的节点的fragment
    KEYED_FRAGMENT = 128,
    // 没有key的children的fragment
    UNKEYED_FRAGMENT = 256,
    // 只有非props需要patch的,比如`ref`
    NEED_PATCH = 512,
    // 动态的插槽
    DYNAMIC_SLOTS = 1024,
    // SPECIAL FLAGS -------------------------------------------------------------

    // 以下是特殊的flag,不会在优化中被用到,是内置的特殊flag

    // 表示他是静态节点,他的内容永远不会改变,对于hydrate的过程中,不会需要再对其子节点进行diff
    HOISTED = -1,
    // 用来表示一个节点的diff应该结束
    BAIL = -2,
}
使用
直接调用函数就行
confirm(opts: IMConfirm)

到这里该知道的就差不多了 接下来我会继续补充的。。。