JS中的事件冒泡问题

onMouseOver,onMouseOut,onClick等都存在事件冒泡

比如代码如下:
<div onClick="alert('你点了div');">
<input type="button" value="div中的按钮" onClick="alert('你点了button')" />
</div>

div中有一个button

事实是,当你单击了按钮,div的onClick事件也会执行,不单是这样,所有button的父级对像都会执行onClick包括body, 这显然不是我们想要的.

解决办法:
阻止事件冒泡
function zuzhi(e){
    if (e && e.stopPropagation ) { //如果提供了事件对象,则这是一个非IE浏览器
        e.stopPropagation();
    }else{//否则,我们需要使用IE的方式来取消事件冒泡 
        window.event.cancelBubble = true;
    }
}
上面的代码就成了这样:
<script type="text/javascript">
function zuzhi(e){
if (e && e.stopPropagation ) { //如果提供了事件对象,则这是一个非IE浏览器
 e.stopPropagation();
}
else{//否则,我们需要使用IE的方式来取消事件冒泡 
 window.event.cancelBubble = true;
}
}
</script>
 
<div onClick="alert('你点了div');">
<input type="button" value="div中的按钮" onClick="(function(e){alert('你点了button');zuzhi(e);})()" />
</div>

上面说的是onClick事件,子对像阻止了事件冒泡,但要是父对像的事件,子对像触发怎么怎么办泥?
还是拿一个div和一个button打比方:
<div onMouseOver="document.getElementById('msg').innerHTML+='\r我进来了'" onMouseOut="document.getElementById('msg').innerHTML+='\r我出去了'">
    <input type="button" value="按钮" />
</div>
<div id="msg"></div><!--这里只是用记录事件执行的-->
本来很明了的事情也出错了,你会发鼠标移入button上时候先后执行VID的onMouseOut和onMouseOver事件,其了怪了,这管button什么事.这就是事件冒泡.
这时候我也和处理onClick事件一样给button的onMouseOut 和 onMouseOver事件组织事件冒泡:
<script type="text/javascript">
function zuzhi(e){
if (e && e.stopPropagation ) { //如果提供了事件对象,则这是一个非IE浏览器
e.stopPropagation();
 }
else{//否则,我们需要使用IE的方式来取消事件冒泡
window.event.cancelBubble = true;
}
}
</script>
<div onMouseOver="document.getElementById('msg').innerHTML+='\r我进来了'" onMouseOut="document.getElementById('msg').innerHTML+='\r我出去了'">
    <input type="button" value="按钮" onMouseOut="(function(e){zuzhi(e);})();"  onMouseOver="(function(e){zuzhi(e);})();" />
</div>
<div id="msg"></div><!--这里只是用记录事件执行的-->
啊哦,问题来了,当鼠标进入button时执行了div的onMouseOut,而鼠标出button时执行了div的onMouseOver,头都大了,怎么办?
实验说明当鼠标进入子标签的一定会执行onMouseOut事件,和子事件冒泡似乎无关了.那怎么解决呢.
在这个情况下我两种方法:
1.给onMouseOut执行语句时加个延迟执行.不阻止子对像的事件冒泡,这样操作简单,可能很多效果本事就会用到延迟执行.
<script type="text/javascript">
 
var $in, $out;
 
function M_in() {
    clearTimeout($out);
    $
in= setTimeout(function() {document.getElementById('msg').innerHTML +='\r我进来了'},100)
  }
 
function M_out() {
    clearTimeout($
in);
    $out
= setTimeout(function() {document.getElementById('msg').innerHTML +='\r我出去了'},100)
  }
</script>
<div onMouseOver="M_in();" onMouseOut="M_out();">
  <input type="button" value="按钮"/>
</div>
<div id="msg">
</div><!--这里只是用记录事件执行的-->
这样改了之后你会发现,无论你把鼠标移进按钮还是移出按钮,执行的都好像只执行了 onMouseOver 事件; 有时候虽然多次执行onMouseOver但关不改变什么,就能用这个方法解决;
 
2.执行时判断事件对像是子对像触发,是就停止执行;
IE和其它浏览器用的方法不一样,所以代码会多一点(经过IE6789,FF,Chrome测试);
<script type="text/javascript">
  
function M_out(e) {
    
var obj = document.getElementById('fff');
    
if (window.event && !e.relatedTarget) {
      
if (obj.contains(event.toElement)) {
        
return
      }
    } 
else if (e && e.relatedTarget) {
      
if (obj.contains(e.relatedTarget)) {
        
return
      }
    };
    document.getElementById(
'msg').innerHTML += '我出去了<br/>'
  }
  
function M_in(e) {
    
var obj = document.getElementById('fff');
    
if (window.event && !e.relatedTarget) {
      
if (obj.contains(event.fromElement)) {
        
return
      }
    } 
else if (e && e.relatedTarget) {
      
if (obj.contains(e.relatedTarget)) {
        
return
      }
    };
    document.getElementById(
'msg').innerHTML += '我进来了<br/>'
  }
</script>
<div id="fff" onMouseOver="M_in(event);" onMouseOut="M_out(event);" style="padding:10px; margin:0 auto; width:700px; border:3px solid #00F">
  <input id="bt1" type="button" value="按钮" />
</div>
<div id="msg" style="padding:5px;border:1px solid #00F">
</div><!--这里只是用记录事件执行的-->
说明:mouseover中relatedTarget指向鼠标来自的元素,而mouseout中的relatedTarget指向的是鼠标去向的那个元素。IE中则是toElement和fromElement;
如果直接用JS的事件绑定,判断上会简单很多:
<script type="text/javascript">
  window.onload 
= function() {
    
var obj = document.getElementById("fff");
    
var msg = document.getElementById("msg");
    obj.onmouseout 
= function(e) {
      
if (e) {
        
if (obj.contains(e.relatedTarget)) {
          
return
        }
      } 
else if (event) {
        
if (obj.contains(event.toElement)) {
          
return
        }
      };
      msg.innerHTML 
+= '我出去了<br/>'
    }
    obj.onmouseover 
= function(e) {
      
if (e) {
        
if (obj.contains(e.relatedTarget)) {
          
return
        }
      } 
else if (event) {
        
if (obj.contains(event.fromElement)) {
          
return
        }
      };
      msg.innerHTML 
+= '我进来了<br/>'
    }
  }
</script>
<div id="fff" style="padding:10px; margin:0 auto; width:700px; border:3px solid #00F">
  <input id="bt1" type="button" value="按钮" />
</div>
<div id="msg" style="padding:5px;border:1px solid #00F">
</div><!--这里只是用记录事件执行的-->
 
补充
1. 不是所有的事件都能冒泡。以下事件不冒泡:blur、focus、load、unload。 
2.阻止冒泡并不能阻止对象默认行为。比如submit按钮被点击后会提交表单数据,这种行为无须我们写程序定制。 

 

posted on 2012-06-08 20:49  cnwhy  阅读(956)  评论(2编辑  收藏  举报

导航