同源iframe内嵌Vue3应用路由跳转后点击外部检测失效如何解决
问题解决方案
根因分析
- 路由跳转时,用户点击的导航元素所属的旧路由组件会被Vue立即销毁并从DOM树移除
- 你绑定的click事件是挂载在document上的,等事件冒泡到document触发判断逻辑时,触发点击的元素已经不在DOM中,
el.contains(event.target)会返回false,误判为外部点击
修复方案
最优方案:使用composedPath判断点击路径
event.composedPath()会返回事件触发时冒泡经过的所有节点数组,不受后续元素销毁的影响,兼容性覆盖所有现代浏览器,修改后的指令代码如下:
/* 修复后的vue3点击外部检测指令 */ const clickOutside = { beforeMount: (el, binding) => { el.clickOutsideEvent = event => { // 获取事件冒泡的完整路径,包含已被销毁的触发元素 const path = event.composedPath?.() || [] // 判断路径中是否包含当前绑定指令的元素 const isClickInside = path.some(node => node === el || el.contains(node)) if (!isClickInside) { binding.value() } }; // 开启捕获模式提前处理事件,进一步降低元素销毁的影响 document.addEventListener("click", el.clickOutsideEvent, true); }, unmounted: el => { document.removeEventListener("click", el.clickOutsideEvent, true); } };
兼容低版本浏览器的备选方案
如果需要兼容不支持composedPath的旧浏览器,可以给判断逻辑加短延迟,等路由跳转的DOM更新完成后再执行判断:
const clickOutside = { beforeMount: (el, binding) => { el.clickOutsideEvent = event => { // 延迟10ms执行,等路由DOM更新完成 setTimeout(() => { if (!(el == event.target || el.contains(event.target))) { binding.value(); } }, 10) }; document.addEventListener("click", el.clickOutsideEvent); }, unmounted: el => { document.removeEventListener("click", el.clickOutsideEvent); } };
内容的提问来源于stack exchange,提问作者sunflower seed
相关产品推荐
相关产品推荐

