实现点击空白区域隐藏下拉弹窗

本文探讨了在中后台项目中,如何解决Element UI 的Select、Popover等组件在有iframe时,点击iframe无法隐藏弹窗的问题。通过分析CSS伪类、focus/blur事件及mouseup事件,提出了实现点击空白区域关闭弹窗的解决方案,并详细解析了Element UI的v-clickoutside指令实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景


中后台项目依赖Element UI 组件库,组件库中Select 选择器、Popover 弹出框等组件弹出内容后,点击组件外部区域都可以让内容收回。

但是我们的页面中有iframe标签,点击iframe标签时,弹出内容并没有收回。

为了解决这一个问题,我们需要调研一下Element UI 是如何实现这个功能的。

功能描述


点击下图中的输入框 A,显示弹窗B,点击 A B 以外的区域,弹窗B 收回。
在这里插入图片描述

思路


需求点

  1. 实现select弹出框,能让弹出框显示、隐藏切换
  2. 实现一个点击组件外部区域,能通知到弹出窗状态切换的功能
  3. 可以复用,通用。

思路一:利用CSS伪类:focus :focus-within 通过样式控制

1. 兼容性在这里插入图片描述
在这里插入图片描述
2. 是否支持Iframe
支持

3. 示例代码

<input class="select" type="text"> <div class="pop-wrap">下拉框</div>
.select:focus + .pop-wrap {
   
   
    display: block;
}

4. 备注
不容易封装,对组件结构有要求,必须按照规定的写法写,很难实现即插即用。
组件html布局比较固定,常规弹窗类组件应该遵循单例模式,这里无法做到。
点击弹出内容区域的时候,焦点会失去,需要单独处理。

思路二:监听focus聚焦、blur失焦事件实现

监听document的聚焦事件,通过聚焦发生时的target来控制弹出哪一个弹窗。

1. 兼容性
在这里插入图片描述
focus事件不支持冒泡模式,需要用捕获模式监听。

2. 是否支持Iframe
支持

3. 示例代码

// focus事件监听:
document.addEventListener('focus', handleFn, true);
// focusin事件监听
document.addEventListener('focusin', handleFnr);

4. 备注
其实用聚焦事件与用mouseup事件的处理方式相似,区别在于点击浏览器之外的区域或点击Iframe时,失焦事件会触发,但是mouseup事件不会触发,这也就导致了用mouseup事件在部分场景会失效。
Element UI 采用的方案就是mouseup,至于如何解决mouseup方案带来的问题,接下来会说明。

事件触发的流程:mouseup事件 → focus事件/blur事件 → 事件处理函数 → 弹出/隐藏弹窗

focus/blur事件虽然解决了点击iframe不触发mouseup的问题,但是相比mouseup而言过程有点不可控,mouseupfocus这一步有时候不受控制。

例如:
在页面中聚焦事件后打开弹窗,这个时候你切换应用,这时候会触发blur事件,回到浏览器窗口时又触发了focus事件,这两步操作其实是多余的。

当然如果你正需要做一个当焦点不在你的网页上时,显示一个蒙层来保证隐私,focus是一个很好的选择。

思路三:监听mouseup事件实现

监听documentmouseup事件发生时的target来控制弹出哪一个弹窗

1. 兼容性

2. 是否支持
iframe

3. 示例代码

// mouseup事件监听:
document.addEventListener('mouseup', handleFn);

4. 备注
mouseup事件处理弹窗的弹出与隐藏时,整个过程更加可控。
事件触发的流程:mouseup事件 → focus事件 → 事件处理函数 → 弹出/隐藏弹窗
相比focus省略了一步,整个流程更可控了,但是无法处理浏览器之外的情况。

方案分析


确定了具体的方案后,我们需要确定实现该方案的主要逻辑

  1. 有一个下拉选择组件,他们提供handleSelectOpen 和 handleSelectClose 方法;
  2. 有一个主题对象,用来收集 组件,主题对象拥有触发 组件们 执行 handleSelectClose的能力
  3. 往主题对象添加组件的能力
  4. 发布事件消息的能力,能通知主题对象执行的能力

其实就是一个观察者模式的实践。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值