关于函数式弹窗组件遇到的问题

好久没写博客了。其实也不是没写,只是没发布到的网上。

这回记录一个在开发函数式组件中碰到的问题。

开门还是不要见山

起因是这样的,入职现在这家公司后,发现有些代码习惯挺不适合我的,就是不习惯,没事那就折腾嘛。所以就有了接下来的故事。

废两句话,首先说碰到什么问题呢?

公司组件库二开了elementplus的table组件,但是没有实现行内编辑以及校验的功能,所以我又在这个组件基础上再一次封装实现行内编辑以及校验的功能,叫做KwTable。然后公司的弹窗依然是二开的elementplus的eldialog,从搬砖一坤年以来我一直不喜欢这个dialog,单纯因为丑,而且打开一个弹窗需要用标签去使用,再加一个理由就是难用,所以我又二开eldialog实现函数式弹窗,叫做openModal函数。

好的,这两玩意我用得挺爽得,一直到前天周四的时候我发现一个问题,就是通过openModal函数打开的弹窗,这个弹窗里用到了kwtable就会报错,是表格透传插槽的v-for里报的,说是不能从undefined上读取值。同时还有一个问题就是通过openModal打开的弹窗里面使用的组件统统都要手动引入注册一遍,明明我已经全局注册了。但是为了不影响业务开发和进度,我选择了先回避这个问题,想着之后有时间再解决吧,于是我在弹窗里就没用kwtable了。

到了昨天周五,另一个同事也用了openModal和kwtable,好家伙他发现出错了,直接找到我前端组长和我导师,他两一顿检查一直盯着表格看(因为是表格报错),没发现有什么异常,于是就找我了,因为他们知道kwtable是我封装的,很显然我知道问题在哪里,我没急着解决.....你们就碰到问题了,没事不慌,只能说”没急着解决“变成”现在必须解决“了。

上伪代码

function openModal() {
        const mountDiv = document.createElement('div');
        mountDiv.id = 'dialog';
        const divDom = document.body.appendChild(mountDiv);
        render(
            h(
                ElDialog, 
                {
                    modelValue: true,
                    title: '标题',
                    onClosed: () => {
                        render(null, divDom);
                        divDom.remove();
                    }
                },
                {
                    default: () => h(HelloWorld, null)
                }
            ),
            divDom
        );
    }

这段代码,再简单不过了,先创建一个div作为容器等下把弹窗通过他渲染,给他设置id,再把他添加到文档body下,与vue的#app同级,接着再使用h函数创建一个虚拟dom,再通过render把他渲染出来,ez。

这段代码在我其他的项目中是正常使用的,没发现任何异常,只有在公司的项目中才发现有古怪,所以我感觉可能受前端项目基建配置插件的影响,比如vue自动导入,elementplus自动导入注册等等。

解决过程

首先出问题了肯定是问gpt,他也没答出个所以然出来,可能是我提问的方式有待进步吧。

然后就去看elementplus源码呗,出发点在ElMessageBox,这个组件是基于vue开发的,凭什么在实际使用中渲染这个组件只需要一行js代码,调用ElMessageBox这个函数就可以渲染组件,而我写的组件就需要在template模板中显示的写出来。其实在elementplus文档上也写了一个”继承应用程序上下文“,突破口就在这里,他暗示我已经很明显了:

从文档示例看到:ElMessageBox({}, appContext)。而我只需要关注elementplus拿这个appContext在内部做了什么处理。

所以,源码,启动!

首先找到MessageBox方法,然后就关注appContext被如何处理,看到上面的代码就明白了,其实他的处理就比我的代码多了一行(76行),也就是 vnode.appContext = appContext,没错就是这一行,把他粘贴到我的代码里

<script setup>
// 伪代码
const { appContext } = getCurrentInstance()!
function openModal() {
        const mountDiv = document.createElement('div');
        mountDiv.id = 'dialog';
        const divDom = document.body.appendChild(mountDiv);
        const vnode = h(
                ElDialog, 
                {
                    modelValue: true,
                    title: '标题',
                    onClosed: () => {
                        render(null, divDom);
                        divDom.remove();
                    }
                },
                {
                    default: () => h(HelloWorld, null)
                }
            );
        vnode.appContext = appContext;
        render(
            vnode,
            divDom
        );
    }

</script>

于是昨天周五完美解决!牛马下班!

 

到此,开头说的问题已经发现原因了:

  • 通过openModal函数打开的弹窗,这个弹窗里用到了kwtable就会报错。因为上下文对象丢失。
  • 通过openModal打开的弹窗里面使用的组件统统都要手动引入注册一遍。因为上下文对象丢失。

 

posted @ 2024-07-27 17:59  写点bug不过分吧  阅读(94)  评论(0)    收藏  举报