利用事件冒泡和阻止事件冒泡的例子

页面中的评分界面,大家一定都很熟悉,现在假如我开了一家饭店,我需要一个在我们的网页上能让顾客对我的饭店进行打分。首先,我们需要两张星星的图片,一张是灰的的星星,一张是黄色的星星,我们分别命名为star.gif和star2.gif。如下图所示:

灰色星星黄色星星

接下来,我们开始编写打分程序的代码:

 <!--相关的html结构-->
 <h1>费墨的饭店</h1>
 <p>hygiene</p>
 <p class="J_rate">
  <img src="star.gif" title="很烂" />
  <img src="star.gif" title="一般" />
  <img src="star.gif" title="还好" />
  <img src="star.gif" title="较好" />
  <img src="star.gif" title="很好" />
 </p>
 <p>price</p>
 <p class="J_rate">
  <img src="star.gif" title="很烂" />
  <img src="star.gif" title="一般" />
  <img src="star.gif" title="还好" />
  <img src="star.gif" title="较好" />
  <img src="star.gif" title="很好" />
 </p>
 <p>flavour</p>
 <p class="J_rate">
  <img src="star.gif" title="很烂" />
  <img src="star.gif" title="一般" />
  <img src="star.gif" title="还好" />
  <img src="star.gif" title="较好" />
  <img src="star.gif" title="很好" />
 </p>
 <script type="text/javascript">
  //DOM,event  package
  var GLOBAL={};
  GLOBAL.namespace=function(str){
    var arr=str.split("."),o=GLOBAL;
    for(var i=(arr[0]=="GROBAL") ? 1:0; i<arr .length;i++){
        //相当于GLOBAL{arr[i]:{}}
      o[arr[i]]=o[arr[i]] || {};
      o=o[arr[i]];
    }
  }
  GLOBAL.namespace("Dom");
  GLOBAL.Dom.getElementsByClassName=function(str,root,tag){
    //是否存在root,并且是否已经与DOM节点挂钩。不存在则赋于document.body
    if(root){
      root=typeof root=="string" ? document.getElementById("root"):root;
    }
    else{
      root=document.body;
    }
    //是否存在tag,不存在则为通配符
    tag=tag||"*";
    //在root里取得tag的数组,arr数组备用储存结果
    var els=root.getElementsByTagName(tag),arr=[];
    //遍历取得的每个标签
    for(var i=0,n=els.length;i<n;i++){
      //遍历标签的每个class
      for(var j=0,k=els[i].className.split(" "),l=k.length;j<l;j++){
          //查找匹配项,并跳出遍历className的循环
        if(k[j]==str){
          arr.push(els[i]);
          break;
        }
      }
    }
    return arr;
  }
  GLOBAL.namespace("Event");
  GLOBAL.Event.on=function(node,eventType,handler,scope){
    //确保node与DOM节点挂钩
    node=typeof node=="string" ? document.getElementById(node) : node;
    scope=scope || node;
    //如果是IE
    if(document.all){
      node.attachEvent("on"+eventType,function(){handler.apply(scope,arguments)});
    }
    else{
      node.addEventListener(eventType,function(){handler.apply(scope,arguments)},false);
    }
  }
  function Rate(rateRoot){
    var root=typeof rateRoot=="string" ? document.getElementById(rateRoot) : rateRoot;
    var items=root.getElementsByTagName("img");
    var imgs=["star.gif","star2.gif"];
    var rateFlag;
    for(var i=0,n=items.length;i<n;i++){
      //记录DOM索引
      items[i].index=i;
      //鼠标滑过效果
      GLOBAL.Event.on(items[i],"mouseover",function(){
        //点击过后,直接跳出,不执行该函数
        if(rateFlag) return;
        //遍历每个星星,如果在点击索引位置之前的变黄色,之后的为灰色
        for(var j=0;j<n;j++){
          if(j<=this.index){
            items[j].src=imgs[1];
          }
          else{
            items[j].src=imgs[0];
          }
        }
      });
      //鼠标滑出,但未点击,所有星星变成灰色
      GLOBAL.Event.on(items[i],"mouseout",function(){
        if(rateFlag) return;
        for(var j=0;j<n;j++){
          items[j].src=imgs[0];
        }
      });
      //鼠标点击,显示打分
      GLOBAL.Event.on(items[i],"click",function(){
        if(rateFlag) return;
        rateFLag=true;
        alert("您打了"+(this.index+1)+"分");
      });
    }
  }
  //实例化rate
  var rateNodes=GLOBAL.Dom.getElementsByClassName("J_rate");
  for(var i=0,n=rateNodes.length;i<n;i++){
    new Rate(rateNodes[i]);
  }
 </script>

在上述代码中,对每个星星监听了mouseover、mouseout和click事件。其效果等同于:

 <p class="J_rate">
  <img src="star.gif" title="很烂" onmouseover="..." onmouseout="..." onclick="..." />
  <img src="star.gif" title="一般" onmouseover="..." onmouseout="..." onclick="..." />
  <img src="star.gif" title="还好" onmouseover="..." onmouseout="..." onclick="..." />
  <img src="star.gif" title="较好" onmouseover="..." onmouseout="..." onclick="..." />
  <img src="star.gif" title="很好" onmouseover="..." onmouseout="..." onclick="..." />
 </p>

之前我们提到过事件冒泡,利用事件冒泡我们可以进一步优化代码。代码如下:

function Rate(rateRoot){
    var root=typeof rateRoot=="string" ? document.getElementById(rateRoot) : rateRoot;
    var items=root.getElementsByTagName("img");
    var imgs=["star.gif","star2.gif"];
    var rateFlag;
    for(var i=0,n=items.length;i<n ;i++){
      //记录DOM索引
      items[i].index=i;
    }
    //鼠标滑过效果
    GLOBAL.Event.on(root,"mouseover",function(e){
      //点击过后,直接跳出,不执行该函数
      if(rateFlag) return;
      var target=e.target || e.srcElement;
      if(target.tagName.toLowerCase() !="img") return;
      //遍历每个星星,如果在点击索引位置之前的变黄色,之后的为灰色
      for(var i=0,n=items.length;i<n;i++){
        if(i<=target.index){
          items[i].src=imgs[1];
        }
        else{
          items[i].src=imgs[0];
        }
      }
    });
    //鼠标滑出,但未点击,所有星星变成灰色
    GLOBAL.Event.on(root,"mouseout",function(e){
      if(rateFlag) return;
      var target=e.target || e.secElement;
      for(var i=0,n=items.length;i<n;i++){
        items[i].src=imgs[0];
      }
    });
    //鼠标点击,显示打分
    GLOBAL.Event.on(root,"click",function(e){
      if(rateFlag) return;
      rateFLag=true;
      var target=e.target || e.srcElement;
      alert("您打了"+(target.index+1)+"分");
    });
  }
  //实例化rate
  var rateNodes=GLOBAL.Dom.getElementsByClassName("J_rate");
  for(var i=0,n=rateNodes.length;i<n;i++){
    new Rate(rateNodes[i]);
  }
 </script>

冒泡的思路是在祖先节点上监听事件,结合event.target/event.srcElement来实现最终效果,其效果等同于如下代码:

<p class="J_rate" onmouseover="..." onmouseout="..." onclick="...">
  <img src="star.gif" title="很烂" />
  <img src="star.gif" title="一般" />
  <img src="star.gif" title="还好" />
  <img src="star.gif" title="较好" />
  <img src="star.gif" title="很好" />
 </p>

利用事件冒泡机制可以让事件挂钩更干净,有效减小内存的开销。

 

阻止事件冒泡

         JS事件流中有一种事件被称为“冒泡事件”,当一个元素被触发一个事件时,该目标元素上的事件会优先被执行,然后向外传播到每个祖先元素,恰如水里的一个泡泡似的,从产生就一直往上冒,到达水平面时,它才消失。在这个过程中,如果你只希望触发目标元素上的事件,而不想它传播到祖先元素上去,那么你需要在“泡泡”离开对象之前刺破它。下面,就以一个简单的Demo来演示下JS如何阻止事件冒泡:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
   <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>js阻止事件冒泡的DEMO</title>
<script type="text/javascript">
	//阻止冒泡的方法
	function stopPP(e)
	{
		var evt = e || window.event;
		//IE用cancelBubble=true来阻止而FF下需要用stopPropagation方法
		evt.stopPropagation ? evt.stopPropagation() : (evt.cancelBubble=true);
	}
</script>
</head>
<body>
<div style="margin: 150px 400px;width: 700px; height: 550px; background-color: #878788;" onclick="alert('最外层div上的onclick事件');">
<h2>最外层div上的onclick事件</h2>
<div style="margin: 100px; width: 500px; height: 300px; background-color: #545444;" onclick="stopPP(arguments[0]);alert('中间层div上的onclick事件');">
<h3>中间层div上的onclick事件</h3>
<div style="margin: 60px 100px; height: 100px; width: 300px; background-color: red;" onclick="stopPP(arguments[0]);alert('最内层div上的onclick事件');">
<h4>最内层div上的onclick事件”</h4>
</div>
</div>
</div>
 
</body>
</html>
posted @ 2012-10-19 10:10  ``炯``  阅读(2426)  评论(0编辑  收藏  举报