星級評分是調查的一個常用功能,網上常見多是動態調用圖片實現的,我結合 CSS 想出一種更簡潔的方法。功能使用更方便,HTML頁源代碼和 JavaScript 語句更簡潔,使用 CSS 排版進一步實現和內容與設計的分享。使用 CSS 用單個圖片做背景,還有個額外帶來的好處,即頁面下載完後作爲背景的那個圖片就已經加載,再動態切換對象的樣式類名時由於用的是同一個圖片文件,所以顯示效果沒有延遲。傳統的換用其它圖片來顯示不同狀態的方法,在加載新圖片時難免會有延遲,除非另用 JavaScript 事先把圖片都下載下來。 基本思路: 星級評分區獨立用一個 div 塊,根據鼠標在此塊內的橫向位置,換算出所在位置和塊寬度的比例,再折算成1-5的數值,如以下範例中塊寬是 80 像素,當鼠標橫座標是27時,(27/80)*5,取上限,可以折算出評分爲2分。 先做HTML頁,最基本的內容是
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <title>星級評分</title>
- <link href="css.css" rel="stylesheet" type="text/css" />
- <script language="JavaScript" src="star.js" type="text/JavaScript"></script>
- </head>
- <body>
- 星級評分。這裏把 input 先做成 text 型的,實際方便調試,實際使用時變成 hidden 型即可。
- <form name="qn" method="post" action="#">
- <input type="text" name="field0" id="field0" />
- <div class="ratingstar" id="field0_star"
- onClick="page.starSet(this, 'field0');"
- onmousemove="page.starHover(this);"
- onmouseout="page.starOut(this, 'field0');">
- <div id="field0_star_hover"></div></div>
- </form>
- </body>
- </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; }
其中 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:
- <font>function getEvent() //同時兼容ie和ff的寫
- {
- if(document.all) return window.event;
- func=getEvent.caller;
- while(func!=null){
- var arg0=func.arguments[0];
- if(arg0)
- {
- if((arg0.constructor==Event || arg0.constructor ==MouseEvent) || (typeof(arg0)=="object" && arg0.preventDefault && arg0.stopPropagation))
- {
- return arg0;
- }
- }
- func=func.caller;
- }
- return null;
- }
- function getMouseWithinX(){
- e = getEvent();
- var mouseX = 0;
- var mouseY = 0;
- //Firefox 雖然 layerY 還不準,但至少 layerX 準了,現在只用橫軸的值就夠
- if(navigator.userAgent.indexOf("Firefox")!=-1){
- return e.layerX;
- }
- //IE 用 offsetX, offsetY 表示鼠標相對所在元素的位置
- else{
- return e.offsetX;
- }
- }
- var page=
- {
- $:function(el)
- {
- return document.getElementById(el);
- },
- starHover:function(obj)
- {
- var mousex = getMouseWithinX();
- //當前對象的寬用 clientWidth
- var intStar = Math.ceil(5 * (mousex / obj.clientWidth));
- var widthStar = intStar * obj.clientWidth / 5;
- var hover = obj.id+'_hover'; //由 HTML 固定寫出顯示星星的內部層了,其名字是外部層id加_hover
- obj.title=intStar+'/5';
- var objHover = this.$(hover);
- objHover.className="ratingstar_hover";
- objHover.style.width = widthStar+'px'; //動態設置寬度要加上 px 字樣!
- },
- starOut:function(obj, container)
- {
- //鼠標移出時讀一下表單項中設定的值,根據那值固定下星星顯示的情況
- if(this.$(container))
- var intStar = this.$(container).value;
- var widthStar = intStar * obj.clientWidth / 5;
- var hover = obj.id+'_hover'; //由 HTML 固定寫出顯示星星的內部層了,其名字是外部層id加_hover
- var objHover = this.$(hover);
- objHover.className="ratingstar_set";
- objHover.style.width = widthStar+'px'; //動態設置寬度要加上 px 字樣!
- },
- starSet:function(obj, container)
- {
- var mousex = getMouseWithinX();
- var intStar = Math.ceil(5 * (mousex / obj.clientWidth));
- var widthStar = intStar * obj.clientWidth / 5;
- var hover = obj.id+'_hover';
- var objHover = this.$(hover);
- objHover.className="ratingstar_set";
- objHover.style.width = widthStar+'px'; //動態設置寬度要加上 px 字樣!
- if(this.$(container))
- this.$(container).value=intStar;
- }
- }
- </font><span style="font-family: Courier New;">
- </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中事件與其元素及鼠標的關係。如果哪位同仁有所見解,歡迎留言交流。