DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> jQuery入門知識 >> JQuery特效代碼 >> jQuery插件-jRating評分插件源碼分析及使用方法
jQuery插件-jRating評分插件源碼分析及使用方法
編輯:JQuery特效代碼     
該插件被廣泛應用於各種需要評分的頁面當中,今天作為學習,把源碼拿出來分析一下,順便學習其使用方法。
一、插件使用一覽
. 代碼如下:
<div>
<div>第一個例子</div>
<div id="16_1" class="myRating"></div>
</div>

. 代碼如下:
<link href="Script/jRating/jRating.jquery.css" rel="stylesheet" type="text/css" />
<script src="Script/jquery-1.7.min.js" type="text/javascript"></script>
<script src="Script/jRating/jRating.jquery.js" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
$(".myRating").jRating({
length:10
});
});
</script>

執行效果

可以看到,上面的例子中,有10顆星,是參數length的作用。其中,默認總分是20分,就是10顆星都選擇。這裡我們著重注意<div>的id16_1,其中16被用來初始化評分插件默認選擇的比例,16/20 * 10。所以我們上面有8顆星是黃色的。

當我們把鼠標放到插件上時,小星星會隨著鼠標移動而增加或減少(紅色會覆蓋黃色或白色),表示評分的從0至20,但點擊鼠標時,評分結束,插件不能再編輯了,同時,通過Ajax向指定的路徑POST數據,用後台數據將評分數據持久化。

在分析源代碼之前,我們先看一下使用該插件時有哪些可選參數:

二、插件源碼分析

按照jQuery插件開發的推薦方法,為了避免快捷符號“$”與其他JavaScript插件產生沖突,源碼開頭采用了下面技術:
. 代碼如下:
(function($) {
$.fn.jRating = function(op) {
//這裡為插件代碼
}
})(jQurery)

接下來,我們分析的所有代碼都將出現在上面綠色區域部分,首先設置默認參數。
. 代碼如下:
var defaults = {
/** String vars **/
bigStarsPath : 'icons/stars.png', // 設置大星星(默認顯示)的相對路徑
smallStarsPath : 'icons/small.png', // 小星星
phpPath : 'php/jRating.php', // 點擊鼠標,評分確定後,將POST數據的地址,接下來我們會采用ASP.Net技術進行處理
type : 'big', // 可以看出,默認是使用大星星
/** Boolean vars **/
step:false, // 如果設置為True,則星星要麼全變色,要麼不全變,當然這也適和選擇分數是同步的。
isDisabled:false, //如果設置為True,則插件不能編輯,當點擊鼠標過後,默認是True的狀態
showRateInfo: true, //當鼠標放到星星上時,是否在鼠標下方顯示選擇比例信息,例如16/20
/** Integer vars **/
length:5, // 星星的個數
decimalLength : 0, // 選擇的數字其後的小數位,最多為3位,如果設置為1,可能出現的情況為16.3/20
rateMax : 20, // 比例中的分母,整數0-9999
rateInfosX : -45, // 信息提示框相對於鼠標位置的橫坐標位置
rateInfosY : 5, // 同上,縱坐標位置
/** Functions **/
onSuccess : null, //成功後的回調函數
onError : null //出錯處理函數
};

通過上面綠色部分的解釋,我們可以看到所有參數的默認值,同時,我們可以在插件使用中,根據需求確定適合的配置,插件的使用不就是這些參數的搭配組合嗎?
接下來我們再看一個函數作用域:
. 代碼如下:
if(this.length>0)
return this.each(function() { //接下來出現的代碼,都將在此處!!!}

這段代碼很簡單,我們要在選中的集合上執行jRating()函數,而上面的代碼首先判斷該集合是否長度大於0,如果為1或者更多,則在該集合上執行each()函數,對集合中的每一個元素(div)進行單獨處理。
該插件的核心代碼其實都在上面的each()函數中,我們首先看幾個函數,這幾個函數都定義在each()函數中,並被其他語句調用。
. 代碼如下:
function findRealLeft(obj) {
if( !obj ) return 0;
return obj.offsetLeft + findRealLeft( obj.offsetParent );
};

首先關注findRealLeft()函數,該函數接收名為obj的對象參數,最後返回該元素對象相對於浏覽器左邊界的距離。注:offsetParent是指元素最近的定位(relative,absolute)祖先元素,如果沒有祖先元素是定位的話,會指向body元素。offsetLeft返回相對於offsetParent的位置。
. 代碼如下:
function getNote(relativeX) {
var noteBrut = parseFloat((relativeX*100/widthRatingContainer)*opts.rateMax/100); //兩個100是否可以去掉,表示選擇的比例,如16 或 16.1
switch(opts.decimalLength) { //根據參數確定要輸去比例需要的小數位,例如16.1 16.12 16.123
case 1 :
var note = Math.round(noteBrut*10)/10;
break;
case 2 :
var note = Math.round(noteBrut*100)/100;
break;
case 3 :
var note = Math.round(noteBrut*1000)/1000;
break;
default :
var note = Math.round(noteBrut*1)/1;
}
return note;
};

接著關注getNote函數,首先我們看以下relativeX是一個什麼東西:
. 代碼如下:
var realOffsetLeft = findRealLeft(this);
var relativeX = e.pageX - realOffsetLeft;

上面兩行代碼是調用getNote函數前,定義relativeX變量用的,我們可以分析出relativeX的作用。這裡的this是我們應用jRating()函數的某個div,首先獲得其相對於浏覽器的左邊距,因為上面兩行代碼是出現在鼠標移動處理函數mouseenter中(稍後我們會看到),因此這裡的e.pageX表示鼠標相對於浏覽器的橫向距離。因此,這裡的relativeX表示的是鼠標相對於<div>左邊界的橫向距離。
我們再次關注getNote函數,由widthRatingContainer = starWidth*opts.length可以看出,widthRatingContainer是左右星星圖片加起來的寬度。因此,var noteBrut = parseFloat((relativeX*100/widthRatingContainer)*opts.rateMax/100);可以把分母與分子上的兩個100去掉,即(relativeX/widthRatingContainer)*opts.rateMax),noteBrut變量最後存儲的是鼠標選擇的比例,如果rateMax設為20,則noteBrut的范圍可以通過鼠標來確定(0—20)。
switch函數,是通過decimalLength參數(用來設定顯示比例的小數位),最終確定(比例)顯示的位數。讀到這裡,我們可以發現,getNote函數就是通過relativX來返回鼠標選擇的比例,這個比例是什麼,見下圖用筆刷框起來的部分:

接下來,我們再關注一個函數
. 代碼如下:
function getStarWidth(){
switch(opts.type) {
case 'small' :
starWidth = 12; // small.png小星星圖片的寬度
starHeight = 10; // 高度
bgPath = opts.smallStarsPath; //圖片相對地址
break;
default :
starWidth = 23; // 大星星的寬度,可以看到,這是默認值
starHeight = 20; // 高度
bgPath = opts.bigStarsPath; //星圖片相對地址
}
};

這個是一個比較簡單的用於初始化變量的函數,根據type屬性,初始化三個變量,分別是starWidth、starHeight、bgPath,綠色的注釋信息已能夠說明一切,不再贅述!
each()中定義的函數看完了,接下來,我們還在each()函數中進行游蕩,按照從上到下的順序,先截取了幾行代碼如下:
. 代碼如下:
var opts = $.extend(defaults, op), //利用extend()函數將默認參數與輸入參數進行合並,最後存儲在opts變量中。
newWidth = 0, //定義變量,該變量用於存儲relativeX,但會根據step屬性進行相應調整
starWidth = 0, //定義變量,星星的寬度
starHeight = 0, //高度
bgPath = ''; //星星圖片地址
if($(this).hasClass('jDisabled') || opts.isDisabled) //確定jDisabled變量,表示是否能對div進行操作
var jDisabled = true;
else
var jDisabled = false;
getStarWidth(); //這個函數不贅述,上面分析過
$(this).height(starHeight); //根據星星的高度,確定此div的高度。

接著往下看
. 代碼如下:
var average = parseFloat($(this).attr('id').split('_')[0]), //通過<div>的id(例如16_2),獲取下劃線前面的數字,把該數字作為默認的選擇比例
idBox = parseInt($(this).attr('id').split('_')[1]), // 下劃線後面的部分,作為辨別評分插件的id
widthRatingContainer = starWidth*opts.length, // 星星圖片寬度總和,並作為外圍容器的寬度
widthColor = average/opts.rateMax*widthRatingContainer, // 顏色塊占用的寬度

接下來,我們將看到新建的三個<div>,並插入到主div中
. 代碼如下:
quotient =
$('<div>',
{
'class' : 'jRatingColor',
css:{
width:widthColor
}
}).appendTo($(this)),
average =
$('<div>',
{
'class' : 'jRatingAverage',
css:{
width:0,
top:- starHeight
}
}).appendTo($(this)),
jstar =
$('<div>',
{
'class' : 'jStar',
css:{
width:widthRatingContainer,
height:starHeight,
top:- (starHeight*2),
background: 'url('+bgPath+') repeat-x'
}
}).appendTo($(this));

首先我們分析第一個<div>,它的類名為jRatingColor,它表示默認比例,用黃色表示,它的長度為withColor,這裡主要看一下它的樣式表:
. 代碼如下:
.jRatingColor {
background-color:#f4c239; /* bgcolor of the stars*/
position:relative; //相對定位
top:0;
left:0;
z-index:2; //這裡需注意,該div的祖先即我們each函數中的this 的z-index是1,下面我們將馬上看到。
height:100%;
}

第二個<div>樣式表如下:
. 代碼如下:
.jRatingAverage {
background-color:#f62929; //紅色
position:relative;
top:0;
left:0;
z-index:2;
height:100%;
}

但在上面的程序中,初始化時,把寬度設為0(因為鼠標還沒選嘛),同時改變了top值:- 星高度,這樣它就和上面添加的div在縱方向上重合了。
接下來看第三個<div>,主要用來放小星星。
. 代碼如下:
/** Div containing the stars **/
.jStar {
position:relative;
left:0;
z-index:3;
}

這個樣式表比較簡單,我們著重看一下JS中動態添加的幾個屬性值:
. 代碼如下:
width:widthRatingContainer, //設置寬度
height:starHeight, //高度
top:- (starHeight*2), //改變縱方向的值,和上面兩個<div>重合
background: 'url('+bgPath+') repeat-x' //設置背景為小星星

屬性的值設置了,但也許有人會問,問什麼只看到小星星顏色是彩色的,而上面添加的前兩個<div>不是具有高度的長方形顏色條嗎?下面我們看一下小星星的圖片就明白為什麼了!

不用多說,旁邊用不透明的背景,中間小星星是透明的,下面的顏色自然就顯示出來了!!
接下來的語句很簡單,就是設置一下最外層div容器的樣式,注意z-Index屬性:
. 代碼如下:
$(this).css({width: widthRatingContainer,overflow:'hidden',zIndex:1,position:'relative'});

接下來會進入相對復雜的部分,我們將關注鼠標動作及其響應效果,首先關注一個小邏輯:
if(!jDisabled)
//接下來的代碼
可以看出,前面我們設置的jDisable變量在這裡用上了,如果jDisabled為true,就表示插件禁用了,那麼接下來的鼠標操作將不會被執行。
接下來看鼠標操作是如何添加到插件中的:
$(this).unbind().bind({//鼠標事件處理代碼,下面將分別進行討論。
});
首先看以一下鼠標進入事件處理代碼
. 代碼如下:
mouseenter : function(e){
var realOffsetLeft = findRealLeft(this);
var relativeX = e.pageX - realOffsetLeft; //首先計算出relativeX,它表示的是鼠標相對於外層<div>左邊界的橫向距離
if (opts.showRateInfo)
var tooltip =
$('<p>',{
'class' : 'jRatingInfos',
html : getNote(relativeX)+' <span class="maxRate">/ '+opts.rateMax+'</span>', //注意這裡用了getNote方法,前面已講了它的用途。
css : {
top: (e.pageY + opts.rateInfosY),
left: (e.pageX + opts.rateInfosX)
}
}).appendTo('body').show();
},

relativeX變量不多解釋,這裡的注釋和前面都有提到,接下來,判斷showRateInfo參數是否為true,如果為true,表示要顯示比例信息(例如鼠標下面顯示16/20),tooltip變量就是這個信息框,最後通過appendTo方法添加到body中。代碼邏輯很簡單,這個函數主要用來顯示提示框<p>,我們在這裡可以重點關注一下<p>節點的樣式,它是絕對定位的,並利用代碼改變了top和Left值,看一下相關的樣式表:
. 代碼如下:
p.jRatingInfos {
position: absolute;
z-index:9999;
background: transparent url('http://www.cnblogs.com/icons/bg_jRatingInfos.png') no-repeat;
color: #FFF;
display: none;
width: 91px;
height: 29px;
font-size:16px;
text-align:center;
padding-top:5px;
}
p.jRatingInfos span.maxRate {
color:#c9c9c9;
font-size:14px;
}

接下來我們看一下鼠標進來後的mousemove事件的處理函數:
. 代碼如下:
mousemove : function(e){
var realOffsetLeft = findRealLeft(this);
var relativeX = e.pageX - realOffsetLeft;
if(opts.step) newWidth = Math.floor(relativeX/starWidth)*starWidth + starWidth;
else newWidth = relativeX;
average.width(newWidth);
if (opts.showRateInfo)
$("p.jRatingInfos")
.css({
left: (e.pageX + opts.rateInfosX)
})
.html(getNote(newWidth) +' <span class="maxRate">/ '+opts.rateMax+'</span>');
},

這個函數主要用來確定鼠標選擇的比例,當然這個比例是通過getNote(newWidth)來得到的,那麼,確定合適的newWidth值就成了這個函數的核心,如果opts.step為true,即比例只能是整數個星星(不能為15.3等等),那麼我們看一下這個邏輯:Math.floor(relativeX/starWidth),starWidth是星星圖片的寬度,Math.floor(-0.1)=-1,Math.floor(0.1) = 0,Math.floor(2.6)=2,知道這些,上面加紅的代碼就很容易理解了。
OK,Let's go on,看一下三個簡單的處理函數
. 代碼如下:
mouseover : function(e){
$(this).css('cursor','pointer');
},
mouseout : function(){
$(this).css('cursor','default');
average.width(0);
},
mouseleave: function () {
$("p.jRatingInfos").remove();
},

mouseover函數確保鼠標進入插件後的顯示樣式,mouseout也是同樣,但它將類名為average的div(紅色的)寬度變成0,mouseleave函數讓提示信息框消失。
最後一個函數,也是整個源碼的結尾,當然也是最重要最復雜的——鼠標點擊函數:
. 代碼如下:
click : function(e){
//接下來的代碼都在此處。
}

我們分部來,先看第一部分:
. 代碼如下:
$(this).unbind().css('cursor','default').addClass('jDisabled');

為什麼這裡只列出一條語句,因為它很重要,但也很簡單,我們這裡一定要關注unbind()函數,它非常非常重要,當點擊鼠標後,首先把其他所有綁定到外圍<div>的事件都去掉了,這樣就鼠標點擊的瞬間,該插件的外觀就固定顯示在浏覽器中,不再隨著鼠標事件而出現變化。當然,最後給<div>添加jDisabled屬性。
我們接著往後走:
. 代碼如下:
if (opts.showRateInfo) $("p.jRatingInfos").fadeOut('fast',function(){$(this).remove();});
e.preventDefault();
var rate = getNote(newWidth); //關注rate變量,後面要用到。
average.width(newWidth);

第一句不難理解,刪除提示信息框,第二句取消鼠標點擊的默認操作,後面兩句很簡單,不再贅述,要知道newWidth在前面已提到,表示鼠標選擇的寬度。
最後一條語句,把選擇的比例發送到服務器端進行持久化操作:
. 代碼如下:
$.post(
opts.phpPath, //利用Ajax技術,向服務端發送數據的地址
{ //Post過去的數據
idBox : idBox,
rate : rate,
action : 'rating'
},
function(data) { //回調函數,主要向插件自定義函數傳遞參數並執行。
if(!data.error)
{
if(opts.onSuccess) opts.onSuccess( element, rate );
}
else
{
if(opts.onError) opts.onError( element, rate );
}
},
'json' //確定如何理解返回的數據,它采用json.
);

利用jQuery做Ajax確實很簡單,代碼中做了必要注釋,這裡不再贅述,這個插件的源碼就分析完了,比較粗,但整個邏輯也許體現了一些,希望該學習筆記對大家能有幫助。下面我們進入實戰階段。
三、實戰jRating插件
為了更加逼近真實應用,我們先利用sql server建立一張數據庫表,它是一個文章類型表,有id、標題、文章內容、評分四個字段,截圖如下:

評分字段默認為-1,表示該文章還沒有被評分。當然,現在有人會說,這個表設計的很不合理,因為一篇文章不會只評分一次吧,應該每個用戶都能進行評論,是的,我們在這裡只是為了演示jRating插件利用Ajax進行持久化操作,因為是演示,所以一切從儉。
新建一個Web頁面,用來顯示第一篇文章(id為1)的標題、內容及評分插件,見前台代碼:
. 代碼如下:
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<link href="Script/jRating/jRating.jquery.css" rel="stylesheet" type="text/css" />
<script src="Script/jquery-1.7.min.js" type="text/javascript"></script>
<script src="Script/jRating/jRating.jquery.js" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
$(".theRating").jRating({
length: 20,
phpPath: 'tempAjax.aspx/UpdateComment' //地址變成了一個aspx類型的WEB頁面下的一個靜態函數,稍後我們會看到!
});
});
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="Label1" runat="server" Text="標題:"></asp:Label>
<asp:Label ID="page1_title" runat="server" Text=""></asp:Label><br />
<asp:Label ID="page1_body" runat="server" Text=""></asp:Label><br />
<div id="16_1" class="theRating"></div>
</div>
</form>
</body>
</html>

後台CS代碼如下:
. 代碼如下:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
tempEntities cbx = new tempEntities(); //用了實體框架獲取數據表
var page1 = cbx.jRatingArticles.Where(m => m.id == 1).SingleOrDefault();
page1_title.Text = page1.title;
page1_body.Text = page1.body;
}
}

為了減少數據庫連接代碼,我用了實體框架,只映射了一張表(jRatingArticle),就是上面我們看到的。獲取id為1的文章對象,並把相應屬性賦值到Label控件的Text屬性中。
頁面效果如下

我們可以看到上面前台頁面的JS代碼中,有這樣一條語句:
phpPath: 'tempAjax.aspx/UpdateComment'
它指明了,當鼠標點擊插件後,要通過Ajax發送數據的地址,這裡我們用.net頁面技術來處理這個異步請求。tempAjax.aspx的後台cs代碼如下:
. 代碼如下:
[WebMethod()]
public static void UpdateComment(int idBox, int rate)
{
tempEntities cbx = new tempEntities();
var page1 = cbx.jRatingArticles.Where(m => m.id == 1).SingleOrDefault();
page1.is_comment = rate;
cbx.SaveChanges();
}

此時,我們還需修改jRating插件的原文件,把鼠標單擊(click)處理函數中的$.post函數替換如下:
. 代碼如下:
$.ajax({
type: "POST",
url: opts.phpPath,
data: '{"idBox":"' + idBox + '","rate":"' + rate + '"}',
contentType: "application/json; charset=utf-8",
dataType: "json"
});

為什麼要改變源文件,因為我想改變Ajax請求的contentType屬性,利用json格式發送請求數據,默認是application/x-www-form-urlencoded
OK,萬事俱備,看一下執行效果(選擇比例為16,16顆紅星嘛):

看看數據庫的變化

試驗成功!今天學習就到這裡,希望此篇學習筆記對大家能有所幫助!
XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved