时代变了,该使用原生popover属性模拟下拉了

这篇文章发布于 2024年01月11日,星期四,23:01,归类于 JS实例。 阅读 8136 次, 今日 5 次 7 条评论

 

封面图

一、事务繁忙,长话短说

目前主流的下拉列表,或者下拉面板的实现方式都是这样的。

点击按钮,让下拉元素显示,绝对定位,同时设置层级,点击空白处,隐藏下拉列表。

其中,每一步都需要JavaScript代码的参与,因此,一个下拉组件的JS代码量还是不容小觑的。

现在,浏览器已经支持原生popover属性,上面这种下拉列表实现方式可以扫进垃圾箱了。我可以这么说,日后使用popover属性实现下拉效果一定是主流实现方案。

因为有两个好处:

  1. 代码极简;
  2. 层级顶级;

例如有如下所示的HTML代码:

<button popovertarget="imgBook">点击显示图片</button>
<img id="imgBook" popover src="/study/202312/book1.jpg" />

无需任何JS代码,点击按钮,就可以让图片显示,点击页面空白处,图片会自动隐藏,实时效果如下:


这就是上面说到的代码极简。

至于层级顶级。

这是Web中专有的一个概念,称为top-layer,元素全屏,或者<dialog>对话框使用showModal()方法显示的时候,都会表现为top-layer,如下图所示:

#top-layer示意

顾名思意就是层级顶级,页面中任何元素都无法覆盖,哪怕z-index设置为999999。

一个页面可以有多个层级顶级元素,至于哪个在最上面,采用的是后来居上的原则,也就是那个后显示,那个就在上面,这个非常符合真实的交互需求。

基于以上两点,popover属性一定是下拉交互的最佳实现。

二、案例演示,一目了然

例如,在LuLu UI中的<select>模拟下拉框的效果是这样的:

lulu ui select 模拟下拉效果

现在要实现此效果,极其简单,只需要让下拉框在显示的时候计算下定位就可以了(默认是浏览器居中定位的)。

HTML结构示意:

<button id="button" popovertarget="select">请选择</button>
<menu id="select" popover>
    <li><input type="radio" name="type" value="">请选择</li>
    <li><input type="radio" name="type" value="1">选项1</li>
    <li><input type="radio" name="type" value="2">选项2</li>
    <li><input type="radio" name="type" value="3" disabled>选项3</li>
    <li><input type="radio" name="type" value="4">选项4</li>
</menu>

使用radio单选框模拟选中行为,可以保持<select>元素的表单特性。

至于显示、隐藏以及层级设置都是popover属性自动完成的,我们无需关心,因此,所有的JS代码其实就下面这一点。

button.onclick = function () {
    const bounding = this.getBoundingClientRect();

    select.style.top = (bounding.bottom + window.pageYOffset) + 'px';
    select.style.left = (bounding.left + window.pageXOffset) + 'px';
    select.style.width = bounding.width + 'px';
};
select.onclick = function (event) {
    if (event.target.type == 'radio') {
        this.hidePopover();
        // 选择文字内容更新
        button.textContent = event.target.parentElement.textContent;
    }
}

是不是简单到瞠目结舌,匪夷所思?

眼见为实,你可以狠狠地点击这里:使用popover属性模拟select下拉demo

下拉模拟效果截图示意

下拉列表各种状态应有尽有。

三、与时俱进,勇攀高峰

popover属性目前所有现代浏览器都支持了,在不久的将来大规模应用已是大势所趋。

popover兼容性

好了,就说这么多吧。

最近忙碌,就不扯淡了。

感谢阅读,欢迎

大人,时代变了

(本篇完)

分享到:


发表评论(目前7 条评论)

  1. wang7说道:

    这种用键盘方向键没法选中菜单,对于习惯纯键盘操作不友好

  2. yutengjing说道:

    不理解为什么要加上 window.pageXOffset,fixed 定位和 boundingClientRect 都是相对于视口的,如果加上 pageXOffset 反而会对不齐。
    测试地址:https://codepen.io/tj-y/pen/oNVYjNY
    测试时先滚动页面再点击打开 popover

  3. 谜底丶土豆说道:

    看来底部的“分享”按钮也可以优化成这种形式了👍🏻

  4. vevan说道:

    估计明年就能正式用上锚点定位了,代码更少了

    写了个demo玩,记得在chrome://flags/里打开Experimental Web Platform features
    https://codepen.io/lunar-dark/full/zYbKgWW

  5. gate120说道:

    这样实现还是有一个经典的下拉框元素在body内的困扰:popover的内容不会随着触发元素滚动(部分客户依然有这样的需求),这样如果再用scroll事件去补的话会很麻烦

  6. meepo说道:

    还必须兼容IE11的我, 一声长叹