星级评分的简化实现

星级评分是调查的一个常用功能,网上常见多是动态调用图片实现的,我结合 CSS 想出一种更简洁的方法。功能使用更方便,HTML页源代码和 JavaScript 语句更简洁,使用 CSS 排版进一步实现和内容与设计的分享。使用 CSS 用单个图片做背景,还有个额外带来的好处,即页面下载完后作为背景的那个图片就已经加载,再动态切换对象的样式类名时由于用的是同一个图片文件,所以显示效果没有延迟。传统的换用其它图片来显示不同状态的方法,在加载新图片时难免会有延迟,除非另用 JavaScript 事先把图片都下载下来。
基本思路:
星级评分区独立用一个 div 块,根据鼠标在此块内的横向位置,换算出所在位置和块宽度的比例,再折算成1-5的数值,如以下范例中块宽是 80 像素,当鼠标横座标是27时,(27/80)*5,取上限,可以折算出评分为2分。
先做HTML页,最基本的内容是
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
  2.   
  3. <html xmlns="http://www.w3.org/1999/xhtml">  
  4.   
  5. <head>  
  6.   
  7. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
  8.   
  9. <title>星级评分</title>  
  10.   
  11. <link href="css.css" rel="stylesheet" type="text/css" />  
  12.   
  13. <script language="JavaScript" src="star.js" type="text/JavaScript"></script>  
  14.   
  15. </head>  
  16.   
  17. <body>  
  18.   
  19. 星级评分。这里把 input 先做成 text 型的,实际方便调试,实际使用时变成 hidden 型即可。  
  20.   
  21. <form name="qn" method="post" action="#">  
  22.   
  23. <input type="text" name="field0" id="field0" />  
  24.   
  25. <div class="ratingstar" id="field0_star"   
  26.   
  27. onClick="page.starSet(this, 'field0');"   
  28.   
  29. onmousemove="page.starHover(this);"   
  30.   
  31. onmouseout="page.starOut(this, 'field0');">  
  32.   
  33. <div id="field0_star_hover"></div></div>  
  34.   
  35. </form>  
  36.   
  37. </body>  
  38.   
  39. </html>  
调用的 css.css 文件中涉及到如下三个样式定义:
.ratingstar,.ratingstar_hover, .ratingstar_set {
 height: 16px;
 width: 80px;
 cursor:pointer; /* border: solid 1px red; cursor: hand; 只有IE支持,pointer 是 FF 和 IE 都支持的手型鼠标*/
 background-image: url(ratingstar.gif);
 background-repeat: repeat-x;
 position:relative; /*解决 Firefox 中获取鼠标位置不准确的问题*/
}
.ratingstar_hover {
 background-position: 0 -32px;
}
.ratingstar_set {
 background-position: 0 -16px;
} 

CSS 用的背景图片

其中 ratingstar.gif 这个图片是个宽16,高48的图片,竖排3个颜色不同的星星,CSS 中使用 background-repeat: repeat-x; 让它横向平铺,再结合整块宽度定义成 width: 80px; 就显示出5个星星了。即整块宽度一定要定义成图片宽度的5倍。 .ratingstar_hover 样式是在动态显示时用的,定义成 background-position: 0 -32px; 是把背景图片上移32像素,则只显示 ratingstar.gif 图片中最下面那个星。而用它的宽度是由 JavaScript 动态指定的,从而可以显示出指定个数的星星。

star.js:

[jscript] view plaincopy
  1. <font>function getEvent() //同时兼容ie和ff的写  
  2.   
  3. {  
  4.   
  5.     if(document.all)   return window.event;  
  6.   
  7.     func=getEvent.caller;  
  8.   
  9.     while(func!=null){  
  10.   
  11.         var arg0=func.arguments[0];  
  12.   
  13.         if(arg0)  
  14.   
  15.         {  
  16.   
  17.             if((arg0.constructor==Event  || arg0.constructor ==MouseEvent) || (typeof(arg0)=="object" && arg0.preventDefault && arg0.stopPropagation))  
  18.   
  19.             {  
  20.   
  21.                 return arg0;  
  22.   
  23.             }  
  24.   
  25.         }  
  26.   
  27.         func=func.caller;  
  28.   
  29.     }  
  30.   
  31.     return null;  
  32.   
  33. }  
  34.   
  35.   
  36.   
  37. function getMouseWithinX(){  
  38.   
  39.     e = getEvent();  
  40.   
  41.     var mouseX = 0;  
  42.   
  43.     var mouseY = 0;  
  44.   
  45. //Firefox 虽然 layerY 还不准,但至少 layerX 准了,现在只用横轴的值就够  
  46.   
  47.     if(navigator.userAgent.indexOf("Firefox")!=-1){  
  48.   
  49.         return e.layerX;  
  50.   
  51.     }  
  52.   
  53.     //IE 用 offsetX, offsetY 表示鼠标相对所在元素的位置  
  54.   
  55.     else{  
  56.   
  57.     return e.offsetX;  
  58.   
  59.     }  
  60.   
  61. }  
  62.   
  63.   
  64.   
  65. var page=  
  66.   
  67. {  
  68.   
  69.     $:function(el)  
  70.   
  71.     {  
  72.   
  73.         return document.getElementById(el);  
  74.   
  75.     },  
  76.   
  77.     starHover:function(obj)  
  78.   
  79.     {  
  80.   
  81.         var mousex = getMouseWithinX();  
  82.   
  83.         //当前对象的宽用 clientWidth  
  84.   
  85.         var intStar = Math.ceil(5 * (mousex / obj.clientWidth));  
  86.   
  87.         var widthStar = intStar * obj.clientWidth / 5;  
  88.   
  89.         var hover = obj.id+'_hover';    //由 HTML 固定写出显示星星的内部层了,其名字是外部层id加_hover  
  90.   
  91.         obj.title=intStar+'/5';  
  92.   
  93.         var objHover = this.$(hover);  
  94.   
  95.         objHover.className="ratingstar_hover";  
  96.   
  97.         objHover.style.width = widthStar+'px';  //动态设置宽度要加上 px 字样!  
  98.   
  99.     },  
  100.   
  101.     starOut:function(obj, container)  
  102.   
  103.     {  
  104.   
  105.         //鼠标移出时读一下表单项中设定的值,根据那值固定下星星显示的情况  
  106.   
  107.         if(this.$(container))  
  108.   
  109.         var intStar = this.$(container).value;  
  110.   
  111.         var widthStar = intStar * obj.clientWidth / 5;  
  112.   
  113.         var hover = obj.id+'_hover';    //由 HTML 固定写出显示星星的内部层了,其名字是外部层id加_hover  
  114.   
  115.         var objHover = this.$(hover);  
  116.   
  117.         objHover.className="ratingstar_set";  
  118.   
  119.         objHover.style.width = widthStar+'px';  //动态设置宽度要加上 px 字样!  
  120.   
  121.     },  
  122.   
  123.     starSet:function(obj, container)  
  124.   
  125.     {  
  126.   
  127.         var mousex = getMouseWithinX();  
  128.   
  129.         var intStar = Math.ceil(5 * (mousex / obj.clientWidth));  
  130.   
  131.         var widthStar = intStar * obj.clientWidth / 5;  
  132.   
  133.         var hover = obj.id+'_hover';  
  134.   
  135.         var objHover = this.$(hover);  
  136.   
  137.         objHover.className="ratingstar_set";  
  138.   
  139.         objHover.style.width = widthStar+'px';  //动态设置宽度要加上 px 字样!  
  140.   
  141.         if(this.$(container))  
  142.   
  143.         this.$(container).value=intStar;  
  144.   
  145.  }   
  146. }  
  147.  </font><span style="font-family: Courier New;">  
  148. </span>前2个函数都是调用现成的库,只为得到鼠标在某个元素范围内的位置,核心算法就在 starHover 函数,思路已经在最前面介绍过了。其它细节说明都在函数中的注释。   

前几天曾经想把页面的 HTML 做到最简化,即只保留 <div class="ratingstar" id="field0_star" onClick="page.starSet(this, 'field0');" οnmοusemοve="page.starHover(this);" οnmοuseοut="page.starOut(this, 'field0');"></div> 而内层的 <div id="field0_star_hover"></div> 由 JavaScript 动态生成,但是发生奇怪的问题:鼠标在 field0_star 范围内移动时貌似会不停触发 onmousemove 和 onmouseout 事件,从而使得两种样式不停切换,显示效果就是闪得厉害。所以暂定现在的方案。

现在的方案中也有遗留的小问题:CSS 中的  position:relative; 是为了解决 Firefox 中获取鼠标位置不准确的问题。如果不加这句,在 Firefox 中 getMouseWithinX() 得到鼠标位置貌似不是期望的相对 field0_star 的位置,而是相对页面的位置,所以值会过大,效果就是鼠标一移上去就会显示多于5个星星。要把这几个问题搞清,还需要进一步弄清楚IE和FF中事件与其元素及鼠标的关系。如果哪位同仁有所见解,欢迎留言交流。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章