Popover的中文意思是弹出框或者弹出窗口,是指在用户与一个控件元素(通常是一个按钮或链接)交互时,出现在屏幕上的临时信息、选项或其他内容。主要是为了是向用户提供额外的信息、选项或功能,而不必离开当前页面或上下文。
在日常开发中,我们就能用到很多弹出框内容,比如Element-Plus等组件库中的反馈组件中的大部分组件都属于弹出框内容:
MDN对Popover API(以下简称)的定义描述是:
Popover API为开发人员提供了一种标准、一致、灵活的机制,用于在其他页面内容之上显示弹出框内容。弹出框内容可以使用HTML属性进行声明性控制,也可以通过JavaScript进行控制。
是不是与HTML <dialog>元素很像,它们都是用户与某个元素进行交互之后在屏幕上弹出内容。但是Popover API创建的弹出框始终是非模态(弹出框显示时仍然可以与其它页面内容交互)的,而<dialog>可以通过JavaScript的方式创建出模态(弹出框显示时不能与其它页面内容交互)对话框。
另外,两者创建的弹出内容(<dialog>需要模态对话框)都会放到顶层中,但是Popover API创建的弹出框层级在<dialog>之上。
Popover API比较简单,只有一个相关的接口,主要还是对HTML属性、CSS伪类和伪元素还有其它接口的扩展,通过Popover API来创建弹出框有声明式和编程式两种方式。需要注意:
- 弹出框元素可以是块级元素、行内元素或者替换元素,但不能是行内块元素,这会始终显示弹出框(非顶层)。
- 注意浏览器兼容性:
声明式创建弹出框
声明式是通过HTML popover、popovertarget和popovertargetaction属性创建和控制弹出框。
<button popovertarget="mypopover">打开/关闭弹出框</button>
<div id="mypopover" popover>一个弹出框</div>
其中:
| 属性 | 值 | 简介 |
|---|---|---|
popover | 1. auto(默认值):弹出框显示时,可以通过点击弹出框区外的区域(对应的按钮控件除外)来隐藏弹出框,因此页面上只会同时显示一个弹出框内容。2. manual:弹出框显示时,只能通过再次点击对应的控件按钮才能隐藏弹出框。这甚至连ESC键都不能隐藏弹出框。这就导致如果没有点击对应的控件按钮隐藏弹出框,页面上可能会同时出现多个弹出框(后来者居上)。 | 用于将元素指定为弹出框元素,元素的display默认为none。 |
popovertarget | 应用了popover属性的元素的id。 | 应用在<button>或按钮类<input>上,将元素转换为弹出/隐藏控件按钮。 |
popovertargetaction | hide、show和toggle:分别表示对元素进行交互会隐藏、显示和在显示/隐藏之间切换。 | 用于控制指定了popovertarget属性的<button>或按钮类<input>应该执行什么操作。 |
编程式
编程式是通过Javascript使用相应API属性、方法或事件来创建和控制弹出框。接下来,我们先来学习这些内容。
对其它接口的扩展
对其它接口的扩展包括:
| 属性/方法 | 值/参数 | 简介 |
|---|---|---|
HTMLElement.popover | auto/manual | 获取/设置元素的popover属性。 |
HTMLButtonElement.popoverTargetElement或 HTMLInputElement.popoverTargetAction | 弹出框元素的Javascript引用(不是字符串ID) | 获取/设置控件对应的目标弹出框元素。相当于获取/设置HTML popovertarget属性。 |
HTMLButtonElement.popoverTargetAction或 HTMLInputElement.popoverTargetAction | hide、show和toggle | 获取/设置控件元素应该执行什么操作。相当于获取/设置HTML popovertargetaction属性 |
HTMLElement.hidePopover() | - | 将弹出框元素从顶层移除,并隐藏。如果弹出框元素已被隐藏则会报错。 |
HTMLElement.showPopover() | - | 将弹出框元素放到顶层显示。如果弹出框元素已经显示则会报错。 |
HTMLElement.togglePopover(force) | force:使该方法的行为类似showPopover()/hidePopover()。1. 如果值为 true,则显示最初隐藏的弹出框。2. 如果值为 false,则隐藏最初显示的弹出框。 | 将弹出框元素在显示/隐藏状态中切换。 |
接口
Popover API只有一个ToggleEvent事件接口,用于对在弹出框元素在显示与隐藏状态切换之间做出响应。
构造函数:
new ToggleEvent(type, init)
其中:
type是一个事件类型的字符串,值始终是toggleevent。init是包含以下属性的对象:{ // 两个只读属性分别表示“正在从什么状态转换”和“正在转换到”的状态,可选值有open和closed oldState: String newState: String, }
我们不需要对这个接口进行操作,实际上它是beforetoggle和toggle事件的事件对象。我们只需要在弹出框元素上监听这两个事件即可,oldState和newState可以通过事件对象(e)中获取:
popoverElement.addEventListener('beforetoggle', (e) => {
if (e.newState === 'open') {
console.log("正在显示弹出窗口");
} else {
console.log("正在隐藏弹出窗口");
}
})
下面是一个完整的编程式🌰:
相关CSS伪类和伪元素
:popover-open
:popover-open伪类是Popover API的内容,匹配已经显示的通过Popover API创建的的弹出框,但是不匹配<dialog>。
该伪类不限制属性,通常用于设置弹出框的进/退场动画、弹出框的显示位置等等。
::backdrop
::backdrop伪元素表示一个视口大小的框,紧挨着顶层中显示的任何元素的下方单独显示。通常用于在某些情况下覆盖整个视口的背景。比如对话框(<dialog>)、弹出框处于全屏模式的元素等等。
它并不是Popover API的内容,但是也能将样式应用到弹出框下方的遮罩层,不过这一点浏览器兼容性很差。
🌰:
写在最后
现在我们已经学习完了Popover API,但是你会发现,这怎么跟那些组件库的Popover组件不一样啊?而且怎么Popover API创建的弹出框默认跟<dialog>模态对话框看着没区别啊?
确实,从样式上看它们不能说毫不相干,简直是一模一样。这点可以从MDN对Popover API的描述来理解:
意思是:
网络上一种非常常见的模式是将内容显示在其他内容的顶部,将用户的注意力吸引到需要采取的特定重要信息或操作上。这些内容可以有几个不同的名称-覆盖、弹出窗口、弹出框、对话框等。我们将在整个文档中将它们称为popover...
所以在本文开头我会用Element-Plus的反馈组件来举🌰。目前如果需要做到像组件库中效果,还需要配合其它API或者是自己手动来实现。