好久沒寫博了,一直以來都太忙了:進入到後半學期後,每周要上四次課,每天都要備課,有點時間就趕工,沒時間寫。儘管如此,剛剛解決的用戶端頁面用javascript實現的表格排序,還是要記錄下來。
需求背景:系統中的一個統計功能,速度較慢,按照之前的做法,是通過把結果表格的表頭文字做成連結,向伺服器提交排序的列名和排序方式(升序/降序),然後重新從服務端返回結果來實現的排序。但是,這種方法無疑效率很差,加重了網路通訊和伺服器的負擔。於是考慮用javascript在用戶端頁面對結果清單排序。
說實話,這種方法以前還真沒接觸過,上網查了一下,發現其實已經不是什麼新鮮的辦法了。能找到很多,我覺得cloudgamer做得很好(http://www.cnblogs.com/cloudgamer/archive/2008/10/06/1304414.html),實現了對包括複選框、單選框列在內的各種類型的table列排序。可惜的是,在我的項目中沒有應用成功,不知道跟在rails中使用RJS有關。後來,又找到了利用javascript中的moveRows方法,移動table中的行的方法,而且有一個現成的代碼可用。但是發現該代碼只是將行的順序顛倒,而不能對亂序的行真正排序。不過這個方法很有啟發性。最終,結合在網上又找到的javascript實現的排序演算法,自己最終實現了針對本項目的排序方法。
代碼如下:
1、頁面調用的排序函數。其中sorttype=1表示降序,-1表示升序;BubbleSort為冒泡排序法。
參數:nColNum為列序號(從0開始);strDataType為所排序的資料類型,如int、float等。
var sorttype = 1; //desc function sortByCol(nColNum,strDataType){ //排序 var table = document.getElementById("tblResult"); //定位到table上 BubbleSort(table,nColNum,strDataType,sorttype); sorttype = 0 - sorttype; //asc }
2、冒泡排序函數。
參數:table為要排序的表格;nColNum為列序號(從0開始);strDataType為所排序的資料類型,如int、float等,函數中根據不同的資料類型,做相應的類型轉換,再比較。
其它:函數主要就是根據傳入的參數,對待排序表格(table)的指定列(nColNum),以某種資料類型(strDataType),按照指定排序方式(nSortOrder,升序/降序),以冒泡排序法排序。其中用類似“table.rows[j].cells[nColNum].childNodes[0].data”這樣的語句,取得table中某一行某個儲存格中的資料。交換兩行時,調用Swap函數。本函數中對int、float類型的資料做了顯式轉換,根據具體需求,可繼續擴充。
需要注意的另外一點,是for(var i=1;i<length;i++)這層迴圈:由於表格的第一行是列名(表頭),故從i=1開始迴圈,而不是i=0。
function BubbleSort(table,nColNum,strDataType,nSortOrder){ //冒泡排序 var length=table.rows.length; for(var i=1;i<length;i++){ //由於表頭還有一行,故i從1開始 var exchanged=false; for(var j=length-1;j>i;j--){ switch(strDataType){ case "int": if(nSortOrder>0){ //desc if(parseInt(table.rows[j].cells[nColNum].childNodes[0].data) > parseInt(table.rows[j-1].cells[nColNum].childNodes[0].data)){ Swap(table,j,j-1); exchanged=true; } } else{ if(parseInt(table.rows[j].cells[nColNum].childNodes[0].data) < parseInt(table.rows[j-1].cells[nColNum].childNodes[0].data)){ Swap(table,j,j-1); exchanged=true; } } break; case "float": if(nSortOrder>0){ //desc if(parseFloat(table.rows[j].cells[nColNum].childNodes[0].data) > parseFloat(table.rows[j-1].cells[nColNum].childNodes[0].data)){ Swap(table,j,j-1); exchanged=true; } } else{ if(parseFloat(table.rows[j].cells[nColNum].childNodes[0].data) < parseFloat(table.rows[j-1].cells[nColNum].childNodes[0].data)){ Swap(table,j,j-1); exchanged=true; } } break; case "string": default: if(nSortOrder>0){ //desc if(table.rows[j].cells[nColNum].childNodes[0].data.toString() > table.rows[j-1].cells[nColNum].childNodes[0].data.toString()){ Swap(table,j,j-1); exchanged=true; } } else{ if(table.rows[j].cells[nColNum].childNodes[0].data.toString() < table.rows[j-1].cells[nColNum].childNodes[0].data.toString()){ Swap(table,j,j-1); exchanged=true; } } } //switch } //for j if (!exchanged) break; } //for i }
3、交換表格行的函數。
參數:table為要交換行的表格;i、j為要交換的兩個行號。
這個函數就是充分利用了table元素的moveRow方法,實現兩行位置的交換。該方法的第一個參數是待移動的行號,第二個參數是移動目標位置的行號。這個函數移動某行後,其它行的位置會做相應調整。根據i、j大小的不同,要想達到最終交換兩行的目的,要分別做兩種不同的操作,如函數中所寫。這個過程很簡單,在紙上畫一畫就能明白了。
function Swap(table,i,j){ if(i<0 || j>table.rows.length-1) return; if(i<j){ table.moveRow(i,j); table.moveRow(j-1,i); } else{ table.moveRow(i,j); table.moveRow(j+1,i); } }
最後,在頁面上只要把表格可排序的列名做成連結調用sortByCol函數即可,如:
<th nowrap>
<a href="#" onclick="sortByCol(0);">學科代碼</a>
</th>
根據BubbleSort函數中的switch,不指定資料類型(即第二個參數)的話,就是預設按照字串類型排序。下面是指定了資料類型的:
<th nowrap>
<a href="#" onclick="sortByCol(2,'float');">百分比(%)</a>
</th>
再有就是,還可用快速排序等其它排序方法實現,相應演算法網上也很容易找到,做相應改造即可。
由於實際應用中,結果未分頁,故這三個函數也未實現對分頁資料的排序。
這個方法的一般性還未仔細考察,留待以後用在其它頁面上時再做。
javascript很強大,還有很多可學的。