要不是用了HTML Popover API,我还在埋头写JavaScript弹窗

2026-08-19 0 330

你说巧不巧,上周产品让我在页面上加一个“用户指南”的弹层,要求不用UI框架,点击按钮就弹出一段说明,点击空白处就关闭。按照以前的老思路,我第一反应是复制一段自己收藏的弹窗JS代码,改改样式,绑定click事件,再写一个点击外部关闭的if判断。但这次我留了个心眼,去MDN上翻了一圈,发现“元素弹窗”早就有原生API了,叫Popover。试了一下,好家伙,我才写了两行HTML,连一行JS都没写,弹窗就能用了。

Popover是什么

简单说,这是一个纯HTML属性,让你任何一个元素能变成“弹层”。这个弹层默认是隐藏的,触发后显示在最上层,并且支持点击页面其他区域自动关闭。用起来跟details标签似的,全靠浏览器干活。

基础用法就是在元素上加上popover属性,然后通过另一个元素的popovertarget属性来指向它。看下面这个最简单的例子:

<button popovertarget="tips">显示提示</button>
<div id="tips" popover>这是一条提示</div>

没错,button不用写onclick,div也不用写display:none。点一下按钮,div就显示出来,再点一下页面别的地方,div就自己消失了。一个JS函数都没写。

你需要知道的几个属性

  • popover:普通属性,加上后元素成为弹层,默认隐藏。
  • popovertarget:触发按钮上使用,值是要弹出的元素id。
  • popovertargetaction:可以指定是show还是hide,或者toggle(默认切换)。

所以如果你想要一个独立的“关闭”按钮,可以这样:

<button popovertarget="tips" popovertargetaction="show">打开</button>
<button popovertarget="tips" popovertargetaction="hide">关闭</button>
<div id="tips" popover>快来试试</div>

连JavaScript的showPopover()hidePopover()都不用调,浏览器自己搞定。

更爽的:点击外部自动关闭

以前做弹窗,最烦的就是点击遮罩或页面其他区域关闭。你得写个监听器,判断点击目标是否在弹窗内部。现在用Popover,浏览器默认支持“light dismiss”,就是点弹层外部区域时自动关闭。这一下就省了十来行监听代码。

如果你不想让它在点击外部时关闭,可以添加manual属性,强制手动关闭。例如:

<div id="pop" popover manual>需要手动关的弹窗</div>

做一个完整实例:消息通知图标

空说无用,直接看一个常见的交互:一个铃铛按钮,点击后弹出几条通知。我用Popover来做,比之前写Vue组件感觉还省事。

<button popovertarget="notify" style="font-size:24px">🔔</button>
<div id="notify" popover>
    <p>你有3条未读消息</p>
    <ul>
        <li>系统维护通知</li>
        <li>有人回复了你</li>
        <li>你的工单已关闭</li>
    </ul>
</div>

我在按钮上直接加了个emoji当铃铛,点一下铃铛弹出来,点屏幕其它地方消失。你甚至可以给popover元素加上max-widthborder样式,让它在视觉上更像真正的弹窗。

有一点需要留意,popover元素会自动获得position: fixed,默认放在页面上方中间(具体位置因浏览器而异)。如果你不想用它默认的对齐方式,可以通过CSS去覆盖它的位置,比如设置margin: auto并配合inset: 0来居中。但由于文章里不打算写样式,这里就点到为止。

和dialog元素有什么区别

我第一次看到popover,脑子里第一反应是“这不就是dialog吗”?其实两者差距很大:

  • dialog需要调用showModal()才会显示并锁住背景,而且默认会带来焦点陷阱,适合模态框。
  • popover更轻量,适合非模态的悬浮提示、气泡面板、快捷菜单等。它不会锁住页面,也不强制管理焦点。

换句话说,如果是一个必须让用户先处理弹窗再继续操作的场景,用dialog;如果只是临时补充信息的悬浮层,用popover更顺手。

还能配合JavaScript做更多事

虽然Popover在纯HTML下已经很能打,但你也完全可以用JS控制。每个popover元素上有showPopover()hidePopover()togglePopover()方法。另外还有beforetoggletoggle事件,可以让你在弹层显示或隐藏时执行额外逻辑。

比如我想在通知弹窗显示时给铃铛加个红点,就可以监听toggle事件:

const notify = document.getElementById('notify');
const bell = document.getElementById('bellBtn');

notify.addEventListener('toggle', (e) => {
    if (e.newState === 'open') {
        bell.classList.add('has-dot');
    } else {
        bell.classList.remove('has-dot');
    }
});

需要注意,toggle事件里的newState只有openclosed两种值,非常清晰。

嵌套Popover需要注意的事

如果你在两个popover元素之间做嵌套(比如一个popover里又有一个按钮打开另一个popover),那就要小心了。因为默认点击外部关闭,如果你点内层popover的触发按钮,外层也一样可能被判定为“点击外部”而关闭。为了避免这种情况,最好使用manual属性,或者用JavaScript控制嵌套的关闭时机。

我实际测试中,这个嵌套场景有点玄学,不同浏览器表现不太一样。所以我的建议是:做简单的popover时,不要嵌套太深。如果需要复杂的级联菜单,还是老老实实用下拉组件库。

一个很大的坑:旧浏览器没法用

网上查了一下,Popover API大概在2023年底开始被Chrome和Firefox支持,Safari也在最近几个版本加入。如果你要支持iOS 15、16那种老设备,那还是别用了。我开发的项目面向内部员工,大家浏览器版本都很新,所以直接用。如果是做面向大众的H5页面,你最好在Can I Use上查一下占比。不过这个API也支持通过polyfill来兼容,但那样就失去了“不写JS”的意义。

总结

Popover API让我最开心的一点是,“弹窗”这种极其常用的交互终于不用再依赖JavaScript了。你可以用几个纯按钮和div拼出一个功能完整的悬浮菜单。尤其适合那种不复杂的提示框:不用动画、不用遮罩、不用焦点管理。省下来的时间多写两行业务逻辑不好吗?

以后再做“出现一个气泡”这种需求,我肯定第一个想起popover,而不是翻开以前的代码库去复制那段已有一百八十行的弹窗插件。

要不是用了HTML Popover API,我还在埋头写JavaScript弹窗
收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

版权声明:
本站资源有的来自互联网收集整理,本站纯免费分享提供学习使用,如果侵犯了您的合法权益,请发送邮件1506151422@qq.com联系,将会及时下架删除。
本站资源仅供研究、学习交流之用,免费开源项目不代表完全可商用,若商业用途请先咨询开发企业能否商用,否则产生的一切后果将由下载用户自行承担。
原创板块未经允许不得转载,否则将追究法律责任。

淘吗网 html 要不是用了HTML Popover API,我还在埋头写JavaScript弹窗 https://www.taomawang.com/web/html/2571.html

常见问题

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务