利用事件冒泡和阻止事件冒泡的例子
页面中的评分界面,大家一定都很熟悉,现在假如我开了一家饭店,我需要一个在我们的网页上能让顾客对我的饭店进行打分。首先,我们需要两张星星的图片,一张是灰的的星星,一张是黄色的星星,我们分别命名为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>
<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>
<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>
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>
<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> |