jQuery中如何在mousedown事件内实现hover事件监听的正常触发?
问题分析与修复方案
先聊聊你的代码为啥没法正常工作,核心问题主要有这几个:
- 层级遮挡问题:
.another_circle初始z-index: -2,比父元素.original_circle的z-index: 0低太多,哪怕你把它移到left:50%,它还是被父元素完全挡住,鼠标根本碰不到它,自然触发不了hover事件。 - 重复绑定事件:你把hover事件绑定放在
mousedown回调里,每次按下鼠标都会给.another_circle多绑一次hover,后续会触发多次重复日志,属于不必要的冗余操作。 - 鼠标按下状态的hover限制:部分浏览器在鼠标按住(mousedown)的状态下,默认不会触发原生hover事件,这时候用
mouseenter/mouseleave配合状态判断会更可靠。
下面是修复后的完整代码,我会逐个说明改动点:
<div class="original_circle" style="border-radius: 50%; background-color: blue; width: 40px; height:40px; z-index: 0; position: relative;"> <div class="another_circle" style="position:absolute; border-radius: 50%; background-color: coral; width: 40px; height:40px; z-index: 1; left: 0; top: 0; display: none;"></div> </div> <div class="original_circle" style="border-radius: 50%; background-color: blue; width: 40px; height:40px; z-index: 0; position: relative;"> <div class="another_circle" style="position:absolute; border-radius: 50%; background-color: coral; width: 40px; height:40px; z-index: 1; left: 0; top: 0; display: none;"></div> </div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script> <script> // 提前绑定鼠标进入/离开事件,避免重复绑定 $('.another_circle').on('mouseenter', function() { console.log('hover mouse in'); $(this).css('background-color', 'red'); }).on('mouseleave', function() { console.log('hover mouse out'); $(this).css('background-color', 'coral'); }); let isMouseDown = false; $('.original_circle').mousedown(function(e) { e.preventDefault(); // 阻止浏览器默认拖拽行为,避免干扰 isMouseDown = true; const $anotherCircle = $(this).find('.another_circle'); $anotherCircle.show().css('left', '50%'); // 显示元素并移动到目标位置 }); $(document).mouseup(function() { isMouseDown = false; $('.another_circle').hide(); // 松开鼠标后隐藏元素,恢复初始状态 console.log('mouse up'); }); // 兼容部分浏览器鼠标按住时不触发mouseenter的问题 $(document).mousemove(function(e) { if (!isMouseDown) return; $('.another_circle').each(function() { const $el = $(this); const rect = $el[0].getBoundingClientRect(); // 判断鼠标是否在元素范围内 const isInElement = e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom; if (isInElement && !$el.data('isHovering')) { $el.data('isHovering', true).trigger('mouseenter'); } else if (!isInElement && $el.data('isHovering')) { $el.data('isHovering', false).trigger('mouseleave'); } }); }); </script>
关键改动说明:
- 调整层级与初始状态:把
.another_circle的z-index改成1(高于父元素的0),初始设置display: none隐藏,同时给父元素加position: relative,让子元素的绝对定位基于父元素。 - 提前绑定事件:把
mouseenter/mouseleave事件提前绑定,避免每次mousedown重复绑定,同时加入了颜色变化的效果,直观展示hover状态。 - 增加鼠标状态标记:用
isMouseDown变量记录鼠标是否处于按住状态,配合mousemove事件做兼容处理,确保在鼠标按住的情况下,也能准确判断鼠标是否在元素上,触发对应的回调。 - 优化交互逻辑:鼠标松开时自动隐藏
.another_circle,恢复初始状态,让交互更流畅。
这样修改后,按住鼠标时,移动后的.another_circle就能正常触发hover相关的回调,日志打印和颜色变化都能正常工作了。
内容的提问来源于stack exchange,提问作者David Foie Gras
相关产品推荐
相关产品推荐

