查看原文
其他

【第2960期】原生 popover 终于要来了!

XboxYan 前端早读课 2023-06-05

前言

作为个人可太欢喜这种浏览器自带的功能了。今日前端早读课文章由 @XboxYan 分享,公号:前端侦探授权。

@XboxYan,阅文体验设计部,专注用户体验相关,热爱 CSS,热爱原生,github:https://github.com/XboxYan

前端早读课:与你分享” 我 “的技术视界

正文从这开始~~

提到 popover,相信大家都很熟悉,没错,就是组件库里经常见到的悬浮层(或者叫 “气泡卡片”),比如 Ant Design。

现在,这个好用的特性终于在 Chrome 114 上正式支持了~下面花几分钟快速了解一下吧

一、popover 属性

其实这个名称以前叫做 popup,后来才更改成了 popover😂。

popover 是一个全局属性。给任意元素添加 popover 以后,它就变成了一个悬浮层。

<div popover>我是悬浮层</div>

popover 有两个值,分别是

  • auto:自动(默认值)。也就是浏览器默认行为,比如点击悬浮层外面会关闭悬浮层,按键盘 Esc 键也会关闭悬浮层

  • manual:手动。也就是没有前面的默认行为,所有操作必须由开发者手动控制。

<div popover>我是悬浮层</div>
<div popover="auto">我是悬浮层</div>
<div popover="manual">我是悬浮层</div>

悬浮层默认是隐藏的,也不能通过属性设置默认显示。那么,如何打开一个悬浮层呢?

二、控制悬浮层的方式

控制悬浮层有两种方式,分别是 声明式 和 命令式

首先来看声明式,经常写原生 HTML 的应该会很喜欢这种方式,无需 JS 介入就可以实现悬浮层的打开和关闭,如下

<button popovertarget="pop1">打开 auto 悬浮层</button>
<div id="pop1" popover>我是 auto 悬浮层</div>

只需要通过 popovertarget 属性将目标悬浮层的 id 属性和按钮相关联就行了(注意,只能是 ID),效果如下

还可以通过 popovertargetaction 属性来设置点击行为,有三个值,分别是

  • show:打开。

  • hide:关闭。

  • toggle:切换(默认值)。如果悬浮层是关闭的就打开,反正亦然

<button popovertarget="pop1" popovertargetaction="show">打开 auto 悬浮层</button>
<button popovertarget="pop1" popovertargetaction="hide">关闭 auto 悬浮层</button>
<button popovertarget="pop1" popovertargetaction="toggle">切换 auto 悬浮层</button>
<div id="pop1" popover>我是 auto 悬浮层</div>

效果如下

现在回过头来看看两种 popover 的区别

<button popovertarget="pop1">切换 auto 悬浮层</button>
<button popovertarget="pop2">切换 manual 悬浮层</button>
<div id="pop1" popover>我是 auto 悬浮层</div>
<div id="pop2" popover="manual">我是 manual 悬浮层</div>

效果如下

可以看到,auto 悬浮层点击空白会自动关闭(还可以通过 Esc 键关闭),而 manual 悬浮层只能手动去关闭。当然大部分情况下 auto 可以满足需求。

三、命令式方式

所谓 “命令式”,其实就是一套 JS API,需要在 JS 中主动去调用。

那么,有了声明式为啥还要命令式呢?答案是,更灵活。

比如,前面的声明式,只适用于 click 场景,如果需要 hover 也能打开悬浮层,这种方式就不行了。像这种情况,就可以采用命令式方式了。

先看语法,很简单,就是 3 个方法

popoverEl.showPopover(); // 打开
popoverEl.hidePopover(); // 关闭
popoverEl.togglePopover(force) // 切换,可传参数,强制设置为 true 或者 false

需要注意的是,这 3 个方式仅适用于悬浮层,也就是必须有 popover 属性,如果是普通元素,会直接报错,如下

还有一种情况,如果一个本来已经打开的悬浮层,再次调用 showPopover (),也会报错,反之亦然

因此,在使用 JS 控制时,推荐使用 manual 悬浮层,便于精准控制。

下面来看一个 hover 控制的例子

<button id="button">hover 打开悬浮层</button>
<div id="pop" popover="manual">我是 hover 悬浮层</div>

然后是相关 JS

button.addEventListener('mouseenter', () => {
pop.showPopover()
})
button.addEventListener('mouseleave', () => {
pop.hidePopover()
})

效果如下

四、判断悬浮层的打开状态

首先,从 HTML 结构上来看,打开和关闭没有任何属性变化,这个和 details 不一样(details 会添加 open 属性)。为此,CSS 还专门出了一个伪类:open 用于标识悬浮层的打开状态

目前还不稳定,后续可能会更变为:popover-open

div[popover]:open{
/* 打开样式 */
}

通过这个伪类,我们可以很轻松的给悬浮层添加过渡动画

[popover]{
display: block; /*默认是display:none,不会有动画*/
visibility: hidden;
opacity: 0;
transform: scale(.6);
transition: .3s;
}
[popover]:open{
visibility: visible;
transform: scale(1);
opacity: 1;
}

效果如下

除了 CSS 方式,JS 也能判断悬浮层的状态,但是并不是自己想象的那样。

起初,我以为有一个属性可以直接获取到悬浮层的状态,发现并不行,如下

popoverEl.open // undefined

那如何获取呢?

其实可以借助前面 CSS 的方式,只要匹配的:open 伪类不就可以了吗,需要用到 matches 方法,https://developer.mozilla.org/en-US/docs/Web/API/Element/matches

这样就能随时获取到悬浮层的打开状态了

popoverEl.matches(':open')

另外,还可以通过事件监听的方式来获取,需要用到新的事件 toggle,这是一个专门针对 popover 新推出的事件,使用方式如下

popoverEl.addEventListener("toggle", (event) => {
if (event.newState === "open") {
console.log("打开状态");
} else {
console.log("关闭状态");
}
});

五、popover 的顶层特性

前面说了那么多,好像并没有什么很厉害的地方,随便一个 div 都可以模拟,而且现在的组件库不是也实现的好好的吗?到底有什么优势呢?

打开控制台可以看到,popover 上有一个很特殊的标识

这个就是顶层 top-layer !也就是层级是最高的,高于页面上的一切。

这也是悬浮层的意义所在,本身就应该是悬浮在最上面。下面是示意图

这样的好处就是无论在 HTML 中的任何位置,都无需担心悬浮层被遮挡的情况,也无需将悬浮层移动的最外层 body 上。

【第1180期】迎接新的 Dialog 元素

Demo:https://codepen.io/xboxyan/pen/MWPrRod

如果浏览器不支持,会有下面提示

这个是用 @supports 实现的

@supports selector([popover]:open) {
.no-support{
display: none ;
}
}

六、兼容性和总结

看一下兼容性,目前只有 Chrome 114 + 支持,内部项目可以尝鲜一下,如果是 Electron 应用,那就大胆使用吧

下面来总结一下本文要点:

  • popover 是一个全局属性。给任意元素添加 popover 以后,它就变成了一个悬浮层。

  • popover 属性有两个值,默认是 auto 自动模式,支持默认行为,比如点击空白关闭,键盘 Esc 关闭

  • popover 属性还支持 manual 手动模式,也就是没有以上默认行为

  • 控制 popover 有两种方式,分别是声明式和命令式

  • 声明式是指通过 HTML 属性来实现点击交互

  • 可以通过 popovertarget 属性将悬浮层的 id 和按钮相关联,这样就能通过按钮打开悬浮层了

  • 还可以通过 popovertargetaction 属性来设置点击行为,有 show、hide、toggle3 种方式

  • 命令式是指通过 JS API 来实现对悬浮层的控制,相比声明式而言更加灵活

  • 控制悬浮层的方法有 showPopover、hidePopover、togglePopover

  • CSS 伪类:open 可以区分悬浮层的打开状态

  • JS 可以通过 matches(':open') 来获取悬浮层的打开状态

  • JS 还可以通过监听 toggle 事件来获取悬浮层的打开状态,方式是 event.newState

  • 相比传统实现,原生 popover 最大的优势是支持顶层特性

关于本文
作者:@XboxYan
原文:https://mp.weixin.qq.com/s/qsZOrUBEjhWGUJ_qzF4XIw

这期前端早读课
对你有帮助,帮” 
 “一下,
期待下一期,帮”
 在看” 一下 。

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存