根本原因是事件监听未覆盖嵌套层级且CSS状态锚点在触屏上不稳定;需用data-toggle统一标记可展开项,结合closest()委托监听、classList.toggle()控制状态,并剥离hover/focus依赖。

移动端多级菜单点击后状态无法保持,根本原因不是 JS 写错了,而是事件监听没覆盖到嵌套层级,或 CSS 类切换被 hover/focus 逻辑干扰——纯 CSS 在触屏上没有稳定的状态锚点。
为什么点击后菜单秒收或根本不展开?
常见现象是:点开“Products”后,“Hardware”子项一闪而过;或点第三级时,第二级直接收起。这不是动画问题,而是 DOM 结构和事件委托没对齐。
- JS 只监听了
.menu-item,但没处理.nested-menu这类深层可展开项 - CSS 里用了
:focus-within或:hover,而 iOS Safari 对非表单元素支持不稳定,安卓 WebView 则可能把首次点击当 hover 触发 - 父级
display: none切换太快,浏览器来不及渲染子菜单,导致视觉上“闪退”
用 data-toggle 统一标记 + 事件委托精准控制
不要靠类名猜层级,给所有可展开项(无论几级)都加 data-toggle="dropdown",再用事件委托接管:
document.addEventListener('click', function(e) {
if (window.innerWidth > 768) return;
const toggleItem = e.target.closest('[data-toggle="dropdown"]');
if (!toggleItem) return;
e.stopPropagation();
const submenu = toggleItem.querySelector('.submenu, .nested-menu');
if (submenu) {
submenu.classList.toggle('is-open');
}
});
-
closest()能穿透嵌套结构,比querySelectorAll('.menu-item').forEach(...)更可靠 -
querySelector('.submenu, .nested-menu')明确限定只找直接子菜单,避免误操作深层节点 - 用
classList.toggle()替代style.display,方便后续加 transition 和无障碍支持
避免点击外部时误关菜单的边界判断
监听全局 click 关闭菜单时,若没排除菜单内部点击,会导致刚点开就收起。
立即学习“前端免费学习笔记(深入)”;
- 检查
e.target.closest('.main-menu'),而不是只看是否在.submenu外 - 特别注意:如果菜单用了
position: fixed,它已脱离文档流,closest()必须基于其实际容器(如.nav-wrapper)而非body - 别用
document.body.addEventListener,改用菜单根容器绑定,减少冲突
最易被忽略的是:同一 DOM 元素上同时存在 :hover、:focus-within 和 JS 的 is-open 类——三者会相互覆盖。移动端必须彻底剥离 hover/focus 依赖,让 JS 成为唯一状态源。否则,哪怕只在某一级漏掉 data-toggle,整个链路就断了。
文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/jiquanzatan/123985.html