JavaScript Mouseover事件异常:hover子菜单时主元素事件仍触发
问题分析与解决
1. 选择器div > ul > li:not(ul)为什么无效?
这个选择器完全起不到过滤作用——:not(ul)是用来排除本身是ul标签的元素,但你选中的目标都是li标签,li不可能是ul,所以这个选择器等价于div > ul > li,根本没法排除子菜单里的li。
如果要选中Element1-4这类顶级主元素li,直接用div > ul > li就足够了:它只会匹配div下直接子ul的直接子li,子菜单里的li嵌套在下级ul中,本来就不会被这个选择器选中。
2. 为什么hover子菜单也会触发事件?
核心原因是事件冒泡:mouseover事件会沿着DOM树向上传递,当你hover子菜单元素(比如2.1)时,它的mouseover事件会冒泡到父级的主元素li,触发你绑定在主元素上的事件监听器,所以看起来子菜单也触发了主元素的事件。
3. 解决方法
有两种简单可行的处理方式:
方式一:改用mouseenter事件
mouseenter和mouseover的核心区别是:mouseenter不会冒泡,只有当鼠标真正进入绑定事件的元素本身时才会触发,进入子元素不会触发父级的mouseenter事件。替换事件类型即可:
const mainItems = document.querySelectorAll('div > ul > li'); mainItems.forEach(item => { item.addEventListener('mouseenter', function() { console.log(this.textContent.trim()); }); });
方式二:在mouseover事件里判断触发源
如果一定要用mouseover,可以在事件处理函数里对比event.target和event.currentTarget:
event.currentTarget是绑定事件的主元素lievent.target是实际触发事件的元素(可能是子菜单里的元素)
只有当两者相同时,才执行打印逻辑:
const mainItems = document.querySelectorAll('div > ul > li'); mainItems.forEach(item => { item.addEventListener('mouseover', function(event) { if (event.target === event.currentTarget) { console.log(this.textContent.trim()); } }); });
内容的提问来源于stack exchange,提问作者shamalamadingdong
相关产品推荐
相关产品推荐

