blog

Bootstrap 下拉菜单(dropdown)鼠标悬浮(:hover)展开功能的更好实现

11 天前UTC+8

Bootstrap 前端框架(或者说只是 UI 库)因为移动设备优先的问题,其 .dropdown 类即便在桌面级也需要点击才能展开,这个问题在互联网并没有找到特别适合的解决方案,故而打算自己实现。

通过观察展开和关闭的 DOM 变化, Bootstrap 5.x 通过 .show 类和 data-bs-popper="static" 来控制展开。

那么一个非常简单的方法,直接控制 .show 类和 data-bs-popper="static" 就可以实现鼠标悬浮来展开菜单。

首先,获取到所有 .dropdown 类,就像这样:

const bsDropdowns = document.querySelectorAll('.dropdown');

之后就可以编写主逻辑了:

bsDropdowns && bsDropdowns.forEach(i => {
    function add() {
        const menu = i.querySelector('.dropdown-menu');
        if (menu) {
            menu.classList.add('show');
            menu.setAttribute('data-bs-popper', 'static');
        };
    };
    function remove() {
        const menu = i.querySelector('.dropdown-menu');
        if (menu) {
            menu.classList.remove('show');
            menu.removeAttribute('data-bs-popper');
        };
    };
    i.addEventListener('mouseenter', add);
    i.addEventListener('click', add);
    i.addEventListener('mouseleave', remove);
    document.addEventListener('click', function (event) {
        !i.contains(event.target) && remove();
    });
    document.addEventListener('touchstart', function (event) {
        !i.contains(event.target) && remove();
    });
});

这是一个非常简单的逻辑,其中定义了 add 和 remove 函数,它们的作用就是控制 .show 和 data-bs-popper 。

通过监听鼠标的 mouseenter 和 mouseleave 事件来确定移出和移入,并执行 add 或 remove 函数。

其中, i.addEventListener('click', add); 的目的是保留点击展开,因为 Bootstrap 的 .dropdown 可以点击后自动判断是展开还是关闭,如果没有保留点击展开,那么当悬停时(展开)点击,就会触发 Bootstrap 的逻辑而被关闭。

最后的监听滑动和点击事件都是为了弥补这段代码的缺陷问题,当滑动或点击目标不是 .dropdown 时就会关闭,与之前的保留点击展开结合,可以实现移动端 点击展开 和 点击其它位置或滑动其它位置关闭 的问题。

ZeoSeven 使用这段代码解决了项目的这一问题,项目使用的是 v5.3.3 ,包括 bootstrap.min.css 和 bootstrap.bundle.min.js ,所以这在 Bootstrap 5.x 中通常可以正常工作,在 v3.x 和 v4.x 中并不确定 ... 不过只要通过展开和关闭的 DOM 变化来确定控制展开和关闭的类或 data- 属性,那么这段代码只需修改 add 和 remove 函数的增加与删除目标,通常也可实现。