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

窗口Resize时菜单事件绑定异常求助:移动端/桌面端交互失效

菜单交互问题修复:响应式切换时的点击事件处理

问题描述

  • 移动端(<768px):首次点击菜单父项展开子菜单,再次点击跳转父级URL,功能正常
  • 桌面端(≥768px):子菜单hover显示,父级<a>标签首次点击应直接跳转URL,但该功能失效
  • 核心问题:resize事件逻辑错误,导致移动端的点击阻止事件在桌面端未被移除,且窗口缩小时事件未正确添加

问题根源

  1. 事件绑定重复且无法移除:原代码中每次调用事件处理函数都会给菜单元素添加新的点击监听,且未保存函数引用,后续无法通过removeEventListener移除
  2. 错误的事件绑定目标:resize时给window添加click事件,而非菜单元素,逻辑完全错误
  3. 无效的事件移除操作:尝试移除DOMContentLoaded事件,但该事件仅触发一次,移除无意义

修复后的完整代码

HTML

<ul class="menu">
  <li class="menu-item-has-children" aria-expanded="false"><a href="#page1/">Page 1</a>
    <ul class="submenu">
      <li><a href="#">subpage 1</a></li>
    </ul>
  </li>
  <li class="menu-item-has-children" aria-expanded="false"><a href="#page2">Page 2</a>
    <ul class="submenu">
      <li><a href="#">subpage 1</a></li>
    </ul>
  </li>
  <li class="menu-item-has-children" aria-expanded="false"><a href="#page3">Page 3</a>
    <ul class="submenu">
      <li><a href="#">subpage 1</a></li>
    </ul>
  </li>
</ul>

CSS

li[aria-expanded="false"] .submenu {
  display: none;
}

li[aria-expanded="true"] .submenu {
  display: block; /* 修复原代码中的笔误zblock */
}

@media screen and (min-width: 768px) {
  ul.menu>li:hover .submenu {
    display: block;
  }
}

JavaScript

document.addEventListener('DOMContentLoaded', function() {
  const menuItems = document.querySelectorAll('.menu-item-has-children');
  // 保存每个菜单元素对应的监听函数,用于后续精准移除
  const listenerMap = new Map();

  // 移动端点击处理逻辑:首次点击展开子菜单,阻止跳转;再次点击正常跳转
  function handleMobileClick(event) {
    const isOpen = this.getAttribute('aria-expanded');
    if (isOpen === 'false') {
      this.setAttribute('aria-expanded', 'true');
      event.preventDefault();
      event.stopPropagation();
    }
  }

  // 根据窗口宽度设置菜单事件
  function setupMenuEvents() {
    const windowWidth = window.innerWidth;
    
    menuItems.forEach(item => {
      if (windowWidth < 768) {
        // 移动端:仅在未添加监听时绑定事件,避免重复绑定
        if (!listenerMap.has(item)) {
          listenerMap.set(item, handleMobileClick.bind(item));
          item.addEventListener('click', listenerMap.get(item));
        }
      } else {
        // 桌面端:移除点击监听,重置展开状态
        if (listenerMap.has(item)) {
          item.removeEventListener('click', listenerMap.get(item));
          listenerMap.delete(item);
        }
        item.setAttribute('aria-expanded', 'false');
      }
    });
  }

  // 初始化时设置一次事件
  setupMenuEvents();

  // resize事件处理:添加防抖避免频繁触发
  let resizeTimeout;
  window.addEventListener('resize', function() {
    clearTimeout(resizeTimeout);
    resizeTimeout = setTimeout(setupMenuEvents, 100);
  });
});

代码说明

  1. listenerMap存储引用:用Map保存每个菜单元素对应的监听函数,确保removeEventListener能精准移除事件
  2. handleMobileClick函数:绑定到菜单元素,通过this访问当前元素,逻辑清晰,避免原代码中嵌套函数的问题
  3. setupMenuEvents核心逻辑:
    • 移动端:仅在未添加监听时绑定事件,避免重复绑定
    • 桌面端:移除监听并重置aria-expanded状态,确保hover逻辑正常工作
  4. resize防抖:添加100ms延迟,避免窗口调整过程中频繁触发事件,提升性能

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 22:10:53