购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

3.2.2 <dialog>元素的不可替代性

下面搬好小板凳,听我好好说说<dialog>元素。

1.<form>元素与对话框自动关闭

对话框元素中往往都会有一两个按钮不参与任何业务逻辑处理,其作用仅仅是关闭对话框,例如Alert类型对话框的确认按钮,或者是对话框右上角的图标字样的关闭按钮。

在过去,这种关闭行为的实现一定是使用JavaScript代码触发的。例如:

或者:

等方法。

实际上,<dialog>元素内置了一种特性,就算不使用JavaScript代码,也能触发对话框的关闭,比如如下所示的HTML代码:

此时,点击“我知道了”按钮,对话框就会立即关闭。

就是这么神奇,不信你可以在浏览器中输入地址https://www.htmlapi.cn/3/2-1.html或扫码访问来体验对应的演示页面。

点击如图3-14所示的按钮,可以看到对话框关闭了。

图3-14 无JavaScript关闭对话框的交互示意

此效果实现的关键是在<form>元素上设置了method="dialog",这是个表单新特性,当设置了此声明后,在提交表单元素的时候,不再刷新页面或打开新窗口,而是关闭当前的<dialog>对话框元素。

而点击按钮触发表单提交的只能是'submit'性质的按钮,因此,万万不可将“我知道了”按钮设置为type="button"或者type="reset"。另外,还可以在'submit'性质的按钮上设置formmethod="dialog"实现同样的对话框关闭效果,例如:

2.关闭来源的判断

<dialog>元素的DOM对象上支持一个名为returnValue的属性,可以自动或手动设置对话框关闭行为的来源。

例如下面这个例子:

这段代码模拟Confirm类型的对话框,点击“确定”按钮会执行一段业务逻辑,然后关闭对话框,点击“取消”按钮则直接关闭对话框。无论是哪个按钮,最终都有关闭对话框这一行为,如果希望区分是哪个按钮触发的关闭,就可以使用这个returnValue属性。

其中有两种给returnValue属性传值的方法:

· 如果点击按钮触发了对话框关闭,则可以在按钮上设置value属性,例如value="cancel";

· 如果使用JavaScript代码触发了对话框关闭,则可以通过给close()方法传参的方式达到我们希望的效果,例如:

此时,我们通过访问dialog.returnValue就可以知道哪个按钮触发了对话框关闭。

眼见为实,你可以通过在浏览器中输入地址https://www.htmlapi.cn/3/2-2.html或扫码访问来体验。

例如,点击“取消”按钮后,页面上就会提示returnValue的值是'cancel',效果如图3-15所示。

图3-15 returnValue属性值示意

如果是通过其他方式关闭的,例如按下ESC快捷键,则returnValue的值会是空字符串。

3.自动聚焦特性

使用原生HTML元素作为前端组件的好处之一就是无障碍访问天然支持,无需额外的自定义。

比如这里的自动聚焦特性。

所谓“自动聚焦”,指的是对话框显示后,浏览器的焦点会自动聚焦到对话框内。

这种特性不仅有助于增强用户体验,还保证了键盘的无障碍访问能力。

还以上面出现过的那段HTML代码为例:

此时,如果我们使用dialog.show()方法让对话框显示,则其中的<input>输入框会自动获取焦点,无须用户再去点击聚焦,效果如图3-16所示。

图3-16 自动聚焦特性示意

类似地,如果是一个Alert提示对话框,则焦点会自动聚焦在“确定”按钮上,此时用户只需要按下回车键,对话框就会关闭,操作非常便捷,无须移动光标到“确定”按钮上,然后再点击。

需要注意的是,这种自动聚焦特性会自动聚焦第一个能够聚焦的元素,而不是智能识别是输入框还是按钮,例如下面这段内容:

此时,对话框打开的焦点则在<a>元素上,不过不要紧,要想聚焦到按钮上,按下Tab键往后索引一下就好了。

这是很多对话框组件所缺失的能力,即忽略键盘的无障碍访问。设想一下,如果对话框打开后,浏览器的焦点不在对话框之中,那么用户想要使用键盘访问对话框里面的内容就会很麻烦,不知道按下多少次的Tab键才能转入对话框元素中(对Tab键行为不清楚的读者,可以参阅第9.1节)。

这里还有一个细节需要注意,<dialog>元素的焦点聚焦特性只有在执行show()或showModal()方法的时候才会触发,如果是使用其他方法让对话框显示的,如以下代码所示,均无法自动聚焦到对话框中。

最后,如果对话框自动聚焦了,那么对话框关闭的时候,焦点会恢复到对话框显示之前的状态,不会影响正常的键盘访问。

4.showModal()方法与真正的对话框

前面几节虽然一直在说“对话框”,但是最终所呈现的效果并非真正意义上的对话框,而更像弹框,层级可控,位置可变,焦点可定义,更重要的是,<dialog>元素背后的元素内容是可以正常交互的。

真正的对话框应该是足够聚焦的(用户只能专注于当前的任务),而不是像一个普通的绝对定位浮层。

这里就不得不提一下<dialog>元素的“王炸”方法——showModal(),让<dialog>元素成为真正的对话框元素。

还是类似的HTML代码:

然后,我们使用showModal()方法让对话框显示,此时的效果如图3-17所示,可以明显看到多了个黑色半透明的模态层,同时除对话框元素以外的元素都无法交互了。

图3-17 showModal()效果与交互阻断

同时,相比show()方法,showModal()显示的对话框的定位方式也变了,不再是绝对定位,而是固定定位,且实现了真正意义上的居中效果。

上述几个明显区别参见表3-1。

表3-1 show()和showModal()显示的对话框的明显区别

你也可以通过在浏览器中输入地址https://www.htmlapi.cn/3/2-3.html或扫码访问来感受一下showModal()方法的样式表现。

模态对话框的半透明背景是可以使用CSS伪元素::backdrop自定义的(<video>视频的黑色背景也可以使用此伪元素进行样式自定义),例如下面这段CSS代码可以让默认的10%的黑色背景变成棋盘网格,效果如图3-18所示。

图3-18 ::backdrop伪元素自定义模态对话框背景

并且我们可以使用:modal伪类区分是普通对话框还是模态对话框。

当然,我对showModal()方法的评价如此之高,并不仅仅因为它多了个模态层,其还带来了现有对话框组件无法模拟的稀缺特性,且不止一个。

5.焦点隔离特性

前面提到show()方法自带聚焦特性,这个showModal()方法也有,除此之外,showModal()方法还有个焦点隔离特性。

即一旦模态对话框显示,则我们的Web页面的焦点只能出现在当前的对话框元素中,对话框之外的元素是不可能获取焦点的,哪怕使用JavaScript代码强制聚焦也不行。

也就是说整个网页中只有图3-19所示的三个元素可以获得焦点。

图3-19 焦点隔离特性示意

此特性极为稀缺,因为如果想要使用JavaScript模拟,仅存在理论上的可能性,例如需要使用HTML inert属性(详见第11.2节的介绍)让<dialog>以外的其他元素全部禁用,这实在太复杂,也不够优雅。

6.顶层特性

使用show()方法让对话框显示,对话框元素的层级是由CSS样式决定的,如果我们希望对话框元素的层级是最高的,则往往需要设置一个数值较大的z-index属性值。

而使用showModal()方法让对话框显示,对话框元素的层级自动最高,无需任何CSS样式设置,此特性被称为顶层特性,有个专门的名词描述此特性,叫作top-layer。

使用开发者工具查看<dialog>元素是可以看到此特性的,如图3-20所示。

图3-20 <dialog>元素的顶层特性

top-layer顶层特性实现的原理比较简单,直接在<html>窗体之外创建一个绘制图层(如图3-21所示),自然可以覆盖页面主体中的所有元素,哪怕页面中的元素的z-index值设置到无穷大也如此。

图3-21 top-layer在<html>窗体之外

但是有时一个页面中可能不止一个<dialog>元素,如果多个模态对话框同时显示,那么层级规则又是怎样的呢?

7.自动层级特性

如果一个页面中有多个对话框通过showModal()方法显示,那么后显示的对话框层级一定最高,这一点和传统的HTML元素不同。

传统的固定定位元素,如果不专门设置层级,则一定是位于DOM树后面的元素的层级最高,而模态对话框的层级高低与DOM位置无关,与呈现的时机有关。

比如下面这个例子,页面中有两个<dialog>元素,先显示第2个<dialog>元素,再显示第1个<dialog>元素。

你会发现,如果使用的是showModal()方法,则第1个<dialog>元素的层级在上面,如图3-22所示。

图3-22 showModal()方法的弹框1在上面显示

如果使用的是show()方法,则第1个<dialog>元素会在下面显示,如图3-23所示。

图3-23 show()方法的弹框1在下面显示

眼见为实,你可以通过在浏览器中输入地址https://www.htmlapi.cn/3/2-4.html或扫码访问来体验。

综合上述7点介绍,<dialog>元素显然不是普通的<div>元素可以模拟的,无论是从用户体验的角度还是从开发成本的角度看,只要想实现对话框效果,毫无疑问,一定优先使用<dialog>元素。 IOzSY5a9KZ7hj7UYkzojlhJSnmydpoBt3K1CQYyYf+kYYQyHqoeHUJLcIl1TKl1M

点击中间区域
呼出菜单
上一章
目录
下一章
×

打开