Vue3实现函数调用组件显示实践

172 阅读2分钟

例如现在有一个弹窗组件,通常的做法是我们会把这个组件放在模板当中,然后会给他传一个响应式变量去控制他是否显示,这样的确是正常写法,但是假如这个组件在很多页面上用到,这个时候就比较头痛了,首先一个就是麻烦灵活性也不够还有一方面就是增加了代码量维护困难,可我们的最佳做法应该是用最少的代码量去实现一个功能,这个时候我了解到了函数式调用组件的实现方式,在此之前也是通过欣赏vant的源码才获得这方面的一个灵感,下面分享给大家如何使用函数式调用组件显示

好的话不多说先看最终效果:

​编辑

实现代码如下 :

/** EVENT: 函数式调用 */
const onClickButton1 = async() => {

    const _result = await showCalendarPro({
        defaultDate: data.selectDate,
        formatter
    })
    if (_result[0]) {

        data.selectDate = _result[0]

    }

}

没错就只有这几行代码,可以看到非常方便

原理其实很简单其实就是利用这个组件去新建一个vue微应用,然后挂载在某个节点上,一般来说我们会挂载在app或者body下面

下面是核心代码实现:

// 默认选项接口

interface IDefaultOptions {
    /** 是否显示 */
    show: boolean
    /** 卸载 */
    unmount: (...args: any[]) => void
}

// 用于过滤掉默认选项的类型工具
type TFilteredDefaultOptions<Target> = Omit<Target, TKeys<IDefaultOptions>>

// 挂载组件
const mountComponent = <Options extends Record<string, any> = Record<string, any>, Result extends any[] = any[]>(
    component: Component,
    options?: TFilteredDefaultOptions<Options>
): Promise<Result> => {

    return new Promise(resolve => {

        // 使用 document.querySelector 查找指定的根节点,如果找不到则使用 document.body
        const _rootNode = document.querySelector('#app') || document.body
        const _mountNode = document.createElement("div")

        const _app = createApp(component, {
            ...options,
            show: true,
            unmount: (...args: Result) => {

                _app.unmount()
                _rootNode.removeChild(_mountNode)
                resolve(args)

            }
        } as IDefaultOptions & TFilteredDefaultOptions<Options>)

        _rootNode.appendChild(_mountNode)
        _app.mount(_mountNode)

    })

}

下面是如何使用mountComponent这个函数很简单

// 显示日历的选项
type TShowCalendarProOptions = TFilteredDefaultOptions<Omit<ICalendarProProps, "poppable" | "selectDate">>

// 日历选择的结果
type TShowCalendarProResult = TCalendarProUnmountParam

// 显示日历
const showCalendarPro = (options?: TShowCalendarProOptions): Promise<TShowCalendarProResult> => {

    return mountComponent<ICalendarProProps, TShowCalendarProResult>(CalendarPro, {
        ...options,
        poppable: true
    })

}

当然组件内部的写法肯定也会有一些不一样,你只需要新增一个unmountprops选项,假如你这个组件是一个弹窗,那么在弹窗关闭的时候执行props.unmount这个函数即可,具体代码实现还请参考vant-pro,这个库是基于vant进行二次封装的,里面有非常详细的代码实现,大家如果觉得好用也可以在项目中使用这个库,可参考使用文档,已经经过我严格的测试了的,最后希望能够给大家代码帮助!