移动端点击/桌面端悬停展开导航下拉菜单的实现问题
导航栏下拉菜单适配问题:桌面端悬停/移动端点击触发异常
需求目标
实现导航栏下拉菜单桌面端(视口宽度>800px)悬停展开,移动端(视口宽度≤800px)点击展开。
基础可行代码(全点击触发)
以下代码可让所有设备均通过点击展开下拉菜单:
$('.anchor').click(function() { $(this).siblings('.navigation__dropdown').slideToggle('slow'); });
自定义异常代码
尝试通过媒体查询区分设备绑定事件,但触发逻辑出现异常:
(function ($) { $(function () { var mq = window.matchMedia('(max-width: 800px)'); mq.addEventListener('change', function () { if (mq.matches) { $('.anchor').click(function() { $(this).siblings('.navigation__dropdown').slideToggle('slow'); } else { $('.anchor').hover(function() { $(this).siblings('.navigation__dropdown').slideToggle('slow'); }); } }); }); }); })(jQuery);
出现的异常问题
- 桌面端宽度加载页面时,下拉菜单完全无法展开
- 调整为移动端宽度,点击可正常展开(符合预期)
- 调回桌面端宽度,悬停可正常展开(符合预期)
- 再次切回移动端宽度,下拉菜单变为悬停触发,此后所有视图均锁定为悬停触发
问题根源与修复方案
核心问题
- 页面初始加载时,未执行事件绑定逻辑,导致桌面端首次加载无触发事件
- 视口切换时,新事件会叠加绑定到
.anchor元素上,旧事件未被移除,最终导致事件逻辑混乱
修复步骤
- 封装事件绑定逻辑为独立函数,方便初始化和切换时调用
- 每次绑定新事件前,先解绑之前的
click和hover事件,避免事件叠加 - 页面加载完成后立即执行一次绑定逻辑,处理初始视口宽度的情况
- 优化
hover逻辑:原slideToggle会导致鼠标移入移出时动画队列堆积,改用mouseenter触发展开、mouseleave触发收起
修复后的代码
(function ($) { $(function () { var mq = window.matchMedia('(max-width: 800px)'); // 封装下拉菜单事件绑定逻辑 function bindDropdownEvents() { // 先解绑所有旧事件,避免事件叠加冲突 $('.anchor').off('click mouseenter mouseleave'); if (mq.matches) { // 移动端:点击触发展开/收起 $('.anchor').click(function() { $(this).siblings('.navigation__dropdown').slideToggle('slow'); }); } else { // 桌面端:悬停展开,离开收起 $('.anchor') .on('mouseenter', function() { $(this).siblings('.navigation__dropdown').slideDown('slow'); }) .on('mouseleave', function() { $(this).siblings('.navigation__dropdown').slideUp('slow'); }); } } // 页面加载完成后立即初始化事件绑定 bindDropdownEvents(); // 监听视口变化,重新绑定对应事件 mq.addEventListener('change', bindDropdownEvents); }); })(jQuery);
内容的提问来源于stack exchange,提问作者pldfs
相关产品推荐
相关产品推荐

