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