大家好,我是前端小喵
一、问题描述
最近在开发vue3+naive-ui的项目,产品突然群里@我,我开发的二次确认popconfirm弹窗组件,点确认后全局有错误提示,提示后popconfirm没关闭
内心os:啊哈,我以前玩vue3+element-plus没碰到这个问题啊,trigger模式下,关闭逻辑不是他们组件库内部处理的嘛,按道理应该都会关闭的;
满脸懵逼回复稍等,我定位一下;带着疑问去看代码了
二、定位问题
看了一下自己的template模板代码和positive-click方法,嗯,没啥问题啊,
方法里面去调保存接口,产品反馈有全局提示,接口返回code的确进入了axios统一响应拦截处理的全局提示错误逻辑,并且return Promise.reject(data); 以前element-plus也是差不多这样写的,应该会提示的。代码如下图
一般像这次二次弹窗确认事件,都是调个保存、删除啥的接口,然后刷一遍数据的逻辑,逻辑都比较简单,所以都是直接写,没包try catch去捕捉异常
然后按照自己的定位问题经验:碰到问题,找系统已上线功能参考。这种常用的组件,我在naive-ui是第一次使用,好家伙,他们和我的一样啊,都是直接调接口,写业务代码,也没包try catch,没对比出差异(后面分析完源码,发现小伙伴吗接口可能对接比较通顺哈哈哈,他们的写法也会碰到我的问题的)
看官方文档:
naive-ui接受函数,该函数返回联合类型 布尔值、promise返回布尔值、any类型
element-plus接受函数,该返回布尔值
naive-ui多了 Promise<boolean | any,any不用管,主要Promise<boolean; 回想我的方法外层async,调接口进入错误提示逻辑,我没有try catch根本不会执行后面的代码,我的这个传入的promise并不会返回boolean,而是代码中止在我的业务逻辑里面,莫非就是这个没try catch导致的问题?那调试一下吧
三、解决办法(都调试过,有兴趣可往后看,看源码分析)
3.1、try catch捕捉异常,catch 里面不return 或者 return true
不return
return true (推荐)
3.2、try catch捕捉异常,catch 里面手动拿popconfirm实例,调里面暴露的setShow方法(分析完源码,其实发现根本没必要了,重要的是catch捕获异常,代码继续运行,就会进入组件库的内置逻辑关闭弹窗)
四、源码分析
带着好奇,为啥element-plus不需要这样,我很清楚记得之前就算confirm也传入一样的事件,它是会关的,naive-ui内部怎么封装的,带着问题我去看了他们的源码
element-plus源码:
好家伙代码就两行,清晰的很,emit调注册的方法,关闭弹窗,难怪我之前confirm注册的方法不需要try catch也会关闭
naive-ui源码:
代码相比element-plus多一些
1、onNegativeClick ? onNegativeClick(e) : true 三元判断,positive-click有注册方法得话,该方法如果返回Promise的话,需返回布尔值,或者方法直接返回布尔值;该没注册positive-click方法,返回true进入then回调;
Promise<boolean被同事点醒了,是为了确认逻辑里面存在多个耦合异步确认流程,一个确认流程影响后面的确认流程
2、positive-click有注册方法 并且注册方法返回值为false的话,直接return 不关闭弹窗(也是为了多个耦合异步确认流程的考虑)
3、onUpdateShow 关闭弹窗方法
function handleNegativeClick(e) {
var _a;
if (!((_a = popoverInstRef.value) === null || _a === void 0 ? void 0 : _a.getMergedShow())) return;
const {
onNegativeClick,
'onUpdate:show': onUpdateShow
} = props;
// onNegativeClick(e)得保证能正常执行不中止,否则不能进入组件内部得then回调
void Promise.resolve(onNegativeClick ? onNegativeClick(e) : true).then(value => {
var _a;
// 为false return,所以前面的不return 或者 return true
if (value === false) return;
(_a = popoverInstRef.value) === null || _a === void 0 ? void 0 : _a.setShow(false);
// onUpdateShow 更新弹窗开启 关闭, popoverBaseProps里面包含'onUpdate:show'
if (onUpdateShow) call(onUpdateShow, false);
});
}
看完源码分析应该知道为啥element-plus和naive在注册方法相同,没有try catch却表现有差异 naive的在多个耦合异步确认流程上考虑多一些,其实我更倾向element-plus的设计,自动关闭弹窗和业务逻辑解耦,如果有多个异步确认流程,我更习惯使用show\visible等属性手动控制
如果大佬们有其他见解,欢迎留言探讨~