窗口Resize时菜单事件绑定异常求助:移动端/桌面端交互失效
菜单交互问题修复:响应式切换时的点击事件处理
问题描述
- 移动端(<768px):首次点击菜单父项展开子菜单,再次点击跳转父级URL,功能正常
- 桌面端(≥768px):子菜单hover显示,父级
<a>标签首次点击应直接跳转URL,但该功能失效 - 核心问题:
resize事件逻辑错误,导致移动端的点击阻止事件在桌面端未被移除,且窗口缩小时事件未正确添加
问题根源
- 事件绑定重复且无法移除:原代码中每次调用事件处理函数都会给菜单元素添加新的点击监听,且未保存函数引用,后续无法通过
removeEventListener移除 - 错误的事件绑定目标:resize时给
window添加click事件,而非菜单元素,逻辑完全错误 - 无效的事件移除操作:尝试移除
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); }); });
代码说明
- listenerMap存储引用:用Map保存每个菜单元素对应的监听函数,确保
removeEventListener能精准移除事件 - handleMobileClick函数:绑定到菜单元素,通过
this访问当前元素,逻辑清晰,避免原代码中嵌套函数的问题 - setupMenuEvents核心逻辑:
- 移动端:仅在未添加监听时绑定事件,避免重复绑定
- 桌面端:移除监听并重置
aria-expanded状态,确保hover逻辑正常工作
- resize防抖:添加100ms延迟,避免窗口调整过程中频繁触发事件,提升性能
内容的提问来源于stack exchange,提问作者luknij
相关产品推荐
相关产品推荐

