You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bootstrap移动端子菜单异常问题排查与修复求助

Bootstrap 移动端下拉菜单异常问题排查与修复

问题描述

我用以下代码实现了Bootstrap导航栏:

<nav class="navbar navbar-expand-lg fixed-top">
    <div class="container">
        <a class="navbar-brand px-5" href="index.php">
          <img src="img/logo.png" width="110" height="70">
        </a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
                aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav">
            <li class="nav-item px-4">
              <a class="nav-link active text-white" href="index.php">Home</a>
            </li>
            <li class="nav-item dropdown">
                <a class="nav-link dropdown-toggle text-white" href="" id="navbarDropdown1" role="button" data-bs-toggle="dropdown"
                   aria-expanded="false">Categories</a>
                <ul class="dropdown-menu">

                  <?php
                  $sql1 = $db->prepare("SELECT * FROM categories WHERE id IN (SELECT parent FROM categories) AND parent = ? AND deleted = ?");
                  $sql1->bind_param('ii', $var0, $var0);
                  $sql1->execute();
                  $result1 = $sql1->get_result();
                  while($row1 = mysqli_fetch_assoc($result1)){
                    $test = $row1['id'];
                    ?>

                    <li class="nav-item dropend">
                    <a class="nav-link active dropdown-toggle" href="" id="navbarDropdown1" role="button" data-bs-toggle="dropdown"
                       aria-expanded="false"><?=$row1['category'];?></a>
                    <ul class="dropdown-menu">

                      <?php
                      $sql2 = $db->prepare("SELECT * FROM categories WHERE parent IN (SELECT id FROM categories) AND parent = ? AND deleted = ?");
                      $sql2->bind_param('ii', $row1['id'], $var0);
                      $sql2->execute();
                      $result2 = $sql2->get_result();
                      while($row2 = mysqli_fetch_assoc($result2)){ ?>

                    <li><a class="dropdown-item" href="category.php?cat=<?=$row2['id'];?>"><?=$row2['category'];?></a></li>

                  <?php } ?>

                  </ul>

                  <?php }
                       $sql3 = $db->prepare("SELECT * FROM categories WHERE id NOT IN (SELECT parent FROM categories) AND parent = ? AND deleted = ?");
                       $sql3->bind_param('ii', $var0, $var0);
                       $sql3->execute();
                       $result3 = $sql3->get_result();
                       while($row3 = mysqli_fetch_assoc($result3)){ ?>

                          <li><a class="nav-link active" href="category.php?cat=<?=$row3['id'];?>"><?=$row3['category'];?></a></li>

                        <?php } ?>

                </ul>
            </li>
          </li>
            <li class="nav-item px-4">
              <a class="nav-link active text-white" href="about.php">About</a>
            </li>
        </ul>
    </div>
    </div>
</nav>

<script>
    document.addEventListener("DOMContentLoaded", function(){
// make it as accordion for smaller screens
        if (window.innerWidth > 992) {
            document.querySelectorAll('.navbar .nav-item').forEach(function(everyitem){
                everyitem.addEventListener('mouseover', function(e){
                    let el_link = this.querySelector('a[data-bs-toggle]');
                    if(el_link != null){
                        let nextEl = el_link.nextElementSibling;
                        el_link.classList.add('show');
                        nextEl.classList.add('show');
                    }
                });
                everyitem.addEventListener('mouseleave', function(e){
                    let el_link = this.querySelector('a[data-bs-toggle]');
                    if(el_link != null){
                        let nextEl = el_link.nextElementSibling;
                        el_link.classList.remove('show');
                        nextEl.classList.remove('show');
                    }
                })
            });
        }
// end if innerWidth
    });
    // DOMContentLoaded  end
</script>

对应的CSS:

.dropdown:hover > .dropdown-menu, .dropend:hover > .dropdown-menu{
  position: block;
  margin-top: .125em;
  margin-left: .125em;
}

@media screen and (min-width:769px){
  .dropend:hover > .dropdown-menu{
    position: absolute;
    top: 0;
    left: 100%;
  }
}

当前遇到的问题:

  • 400x652移动端尺寸下,菜单下拉完全无法工作
  • 500x589尺寸下,主菜单下拉正常,但点击子菜单时会关闭主菜单而非展开子菜单
  • 移除所有CSS后问题仍存在

问题根源

  1. 重复ID冲突:子菜单的下拉按钮使用了和主菜单相同的id="navbarDropdown1",Bootstrap下拉组件依赖唯一ID绑定事件,重复ID会导致事件监听逻辑混乱。
  2. DOM结构错误:代码中存在多余的闭合</li>标签(主Categories的<li>后多了一个</li>),破坏了列表项的嵌套结构,导致移动端下拉逻辑失效。
  3. CSS语法错误:原CSS中position: block是无效属性值,会影响菜单的定位渲染。
  4. 移动端事件冒泡未处理:子菜单点击事件会向上冒泡触发父菜单的关闭逻辑,导致点击子菜单时主菜单被收起。

修复方案

1. 修正重复ID

将子菜单的下拉按钮ID改为唯一值,利用循环中的分类ID生成:

<a class="nav-link active dropdown-toggle" href="" id="navbarDropdown-<?=$row1['id'];?>" role="button" data-bs-toggle="dropdown"
   aria-expanded="false"><?=$row1['category'];?></a>

2. 修复DOM结构错误

删除主Categories的<li class="nav-item dropdown">后面多余的</li>标签(代码中位于</ul>和<li class="nav-item px-4">之间的那个闭合标签),确保列表项嵌套正确。

3. 修正CSS语法错误

将position: block改为有效的position: static(移动端下拉菜单默认静态定位即可):

.dropdown:hover > .dropdown-menu, .dropend:hover > .dropdown-menu{
  position: static;
  margin-top: .125em;
  margin-left: .125em;
}

4. 阻止移动端事件冒泡

修改JS代码,添加子菜单点击事件的阻止冒泡逻辑,避免关闭父菜单:

document.addEventListener("DOMContentLoaded", function(){
    // 桌面端悬停逻辑保留
    if (window.innerWidth > 992) {
        document.querySelectorAll('.navbar .nav-item').forEach(function(everyitem){
            everyitem.addEventListener('mouseover', function(e){
                let el_link = this.querySelector('a[data-bs-toggle]');
                if(el_link != null){
                    let nextEl = el_link.nextElementSibling;
                    el_link.classList.add('show');
                    nextEl.classList.add('show');
                }
            });
            everyitem.addEventListener('mouseleave', function(e){
                let el_link = this.querySelector('a[data-bs-toggle]');
                if(el_link != null){
                    let nextEl = el_link.nextElementSibling;
                    el_link.classList.remove('show');
                    nextEl.classList.remove('show');
                }
            })
        });
    }
    // 新增:阻止子菜单点击事件冒泡
    document.querySelectorAll('.dropdown-menu .dropdown-toggle').forEach(function(toggle){
        toggle.addEventListener('click', function(e){
            e.stopPropagation();
        });
    });
});

5. 确认Bootstrap依赖加载

确保页面已正确引入Bootstrap 5所需的Popper.js和Bootstrap JS文件:

<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.min.js"></script>

内容的提问来源于stack exchange,提问作者Black P

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 05:37:23