如何使用jQuery实现先触发ul hover事件再触发li hover事件
根本原因
出现该触发顺序是浏览器的默认行为:jQuery的hover()方法绑定的是mouseenter和mouseleave事件,这两个事件不会冒泡,触发时机是指针进入元素自身区域时。当从外部移入嵌套在ul内部的li时,指针会先命中层级更具体的li元素,因此li的mouseenter先触发,之后才会触发父元素ul的mouseenter。
解决方案1:微任务延迟li触发逻辑(改动最小)
只需要给li的hover移入回调包裹一层微任务,让它等当前同步任务(包含ul的hover回调)全部执行完再运行,即可满足顺序要求,原有逻辑几乎不用改:
function bindHoverEvents() { $('#list').hover( () => console.log("1. List hover"), () => console.log("4. List unhover") ); $('.list-item').hover( // 用微任务推迟执行,确保ul的hover先跑完 () => Promise.resolve().then(() => console.log("2. Item hover")), () => console.log("3. Item unhover.") ); }
解决方案2:捕获阶段绑定父元素事件(更稳定)
如果业务逻辑比较复杂,担心微任务时序不可控,可以改用支持事件流的mouseover/mouseout事件,把父元素ul的事件绑定在捕获阶段,天然保证父元素事件先于子元素触发:
function bindHoverEvents() { const list = document.querySelector('#list'); // 第三个参数传true代表绑定到捕获阶段,父元素先触发 list.addEventListener('mouseover', (e) => { // 只在进入ul本身时触发,避免子元素冒泡的重复触发 if (e.target === list) { console.log("1. List hover"); } }, true); list.addEventListener('mouseout', (e) => { if (e.target === list) { console.log("4. List unhover"); } }, true); // li的hover事件无需特殊调整 $('.list-item').hover( () => console.log("2. Item hover"), () => console.log("3. Item unhover.") ); }
两种方案运行后,移入再移出li的控制台输出都符合期望的顺序。
内容的提问来源于stack exchange,提问作者tomashauser
相关产品推荐
相关产品推荐

