子div上的点击事件会触发操作,尽管点击处理程序已经在父元素上使用addEventListener设置了(事件冒泡被禁用)。

3

我有三个div盒子

第一个div名为main,id为"main",包含两个其他的盒子,它们的id分别为"menu_header""menu_options"

这是我的html代码

<div id="main">
 <div id="menu_header">
  </div>
  <div id="menu_options">
  </div>
</div>
<span>Something here</span>

这是我的 CSS

#main{
  display:table-cell;
  position:relative;
  top:100px;
  border:solid purple;
}
#menu_header{
  position:relative;
  border:solid black;
  background:red;
  width:100px;
  top:200px;
  height:100px;
 /* -moz-transition-property:bottom;
  -moz-transition-duration:2s;
  transition-property:top;
  transition-duration:1s;*/
}
#menu_options{
  background:blue;
  position:absolute;
  bottom:0%;
  border:solid black;
  width:100px;
  height:100px;
}
/*#menu_header:active{
  top:100px;
}*/

(忽略掉已被注释的 CSS 过渡效果)

以下是我的 JavaScript 代码:

function test(e){
 //if(e.target.id=="menu_options"){return};
 $('#menu_header').animate({top:'-10'},1000);
  //var t=document.getElementById('menu_header')
 // t.setAttribute('top','40px');
  t.style="position:relative;border:solid black;background:red;width:100px;top:60px;height:100px;"
}
document.getElementById('main').addEventListener('click',test,false)

最后这是我的实验jsfiddle链接 http://jsfiddle.net/repzeroworld/ev7k688s/

在这种情况下,当我在id为"main"的父容器上设置一个点击事件处理程序时,除了每次单击此父容器的子div(id为"menu_options")之外,一切都正常工作。

我发现下面的链接,但不知何故,在我的情况下,此处的event.propogation()解决方案似乎无法工作。

单击子元素也会触发其父元素的单击事件

一个不好的解决方法,以防止任何操作执行,如果子div捕获事件,则是

if(e.target.id=="menu_header"){return};

我在我的javascript代码中注释掉了上述内容。

问题: 为什么具有id“menu_options”的子div捕获了父容器具有id“main”的事件,尽管我在addEventListener中设置了false以防止事件冒泡?


2
这是 event.stopPropagation(),而不是 event.propagation()。使用 addEventListener() 设置 false 并不能禁用冒泡。 - user1106925
3个回答

3
原因false传递给.addEventListener()并不能禁用事件冒泡。它只是让事件在冒泡阶段而不是捕获阶段触发。
当事件发生时,它从DOM根开始进入“捕获”阶段。这意味着事件从document到达event.target,沿途触发任何“捕获”处理程序。
一旦它到达event.target,它就会掉头,并向上遍历到document,调用任何“冒泡”处理程序。
所以因为你将false作为第三个参数传递,处理程序将在最后一个“冒泡”阶段被调用。
因此,你可以看到,这并不能防止嵌套元素调用处理程序。
解决方案 如果你仅仅想在单击实际元素本身而不是其子元素时调用处理程序,只需在this不等于e.target时停止处理程序即可。
function test(e){
   if (this != e.target)
      return;

   $('#menu_header').animate({top:'-10'},1000);
   var t=document.getElementById('menu_header')
   t.setAttribute('top','40px');
   t.style="position:relative;border:solid black;background:red;width:100px;top:60px;height:100px;"
}
document.getElementById('main').addEventListener('click',test,false)

这很容易理解!我尝试使用 "if"("this!= e.target");返回"...但什么也没有发生...有什么建议吗? - repzero
我将“this!= e.target”替换为“document.getElementById('menu_options')!= e.target”……坚持我的问题,即要求解释为什么我会遇到这个问题。我会接受这个答案……:D - repzero

1
您可以通过以下两种情况来限制事件冒泡。 1. 在每个DOM对象上放置Click事件,即从子级到父级,并使用event.stopPropagation()。 2. 使用e.target.id识别DOM对象并返回"false"。[我们正在使用此方法]
下面是代码:
<script>
        function test(e) {
            if (e.target.id == "menu_header") { return }
            else if (e.target.id == "menu_options") { return }
            $('#menu_header').animate({ top: '-10' }, 1000);
            var t = document.getElementById('menu_header')
            t.setAttribute('top','40px');
            t.style = "position:relative;border:solid black;background:red;width:100px;top:60px;height:100px;"
        }
         window.onload = function () {
        document.getElementById('main').addEventListener('click', test, false);
    }
</script>

1

尝试在子元素中停止事件传播。请参见此处

function test(){
 $('#menu_header').animate({top:'10'},1000);
  //var t=document.getElementById('menu_header')
 // t.setAttribute('top','40px');
  //t.style="position:relative;border:solid black;background:red;width:100px;top:60px;height:100px;"
}

function stopPropagation(e){
    e.stopPropagation();
}

document.getElementById('main').addEventListener('click',test,false);

document.getElementById('menu_header').addEventListener('click',stopPropagation,false);

这真的很聪明...而且非常漂亮! - repzero
谢谢,如果这是您正在寻找的解决方案,请将其标记为已接受的答案。 - Raman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接