/* SortTable version 2 7th April 2007 Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ Instructions: Download this file Add <script src="sorttable.js"></script> to your HTML Add class="sortable" to any table you'd like to make sortable Click on the headers to sort Thanks to many, many people for contributions and suggestions. Licenced as X11: http://www.kryogenix.org/code/browser/licence.html This basically means: do what you want with it. 用法:将要排序的表格添加CSS,如<table class="sortable"> 对于不需要排序的列,在表头所在行的该列,添加CSS,如<td class="sorttable_nosort"></td> ====================================================================================== Update: version 2.1 9th Mar 2009 Hopesoft , http://www.51ajax.com/blog/ hopesoft@msn.com 说明: 1.增加中文排序 2.增加指定各行使用不同css样式功能(比如奇偶行背景色不一致) 用法:在要表头浮动的表格上添加属性,如<table class="sortable" rowclass="bg1,bg2,bg3"> 3.增加表头浮动功能(支持同一个页面有多个表格,比如不同Tab标签下的各个表格) 用法:在要表头浮动的表格上添加CSS,如<table class="scrolltable"> 另外最好指定“表头”和“数据行”的各列的列宽,如 <tr><td class='w1'>姓名</td><td class='w2'>年龄</td></tr> <tr><td class='w1'>张三</td><td class='w2'>21</td></tr> 以避免在FireFox下表头浮动时表头各列与数据各列不对齐 4.增加页面载入后自动排序 用法:在表格上添加属性autosortcol,对应要自动排序的列号,注意是从0开始 如<table class="sortable" autosortcol="3">,则表示当页面载入成功后,会自动对第4行进行排序 */ var stIsIE = /*@cc_on!@*/false; sorttable = { init: function() { // quit if this function has already been called if (arguments.callee.done) return; // flag this function so we don't do the same thing twice arguments.callee.done = true; // kill the timer if (_timer) clearInterval(_timer); if (!document.createElement || !document.getElementsByTagName) return; sorttable.DATE_RE = /^(/d/d?)[///.-](/d/d?)[///.-]((/d/d)?/d/d)$/; //保存浮动表头信息,格式 sorttable.scrollRows=[]; forEach(document.getElementsByTagName('table'), function(table) { if (table.className.search(//bsortable/b/) != -1) { sorttable.makeSortable(table); //指定各行css样式 sorttable.changeRowCss(table); //页面载入后自动排序 var autosortcol=table.getAttribute("autosortcol"); if(autosortcol){ var columnId=parseInt(autosortcol); if(isNaN(columnId)){return;} var _headrow = table.tHead.rows[0].cells; for (var i=0; i<_headrow.length; i++) { if (columnId==i && !_headrow[i].className.match(//bsorttable_nosort/b/)) { //触发click事件 if(stIsIE){ _headrow[i].fireEvent("onclick");} else{ var evt = document.createEvent('MouseEvents'); evt.initEvent('click',true,true); _headrow[i].dispatchEvent(evt); } break; } } } } //处理表头浮动 if (table.className.search(//bscrolltable/b/) != -1) { sorttable.makeScrolltable(table); } }); }, makeSortable: function(table) { if (table.getElementsByTagName('thead').length == 0) { // table doesn't have a tHead. Since it should have, create one and // put the first table row in it. the = document.createElement('thead'); the.appendChild(table.rows[0]); table.insertBefore(the,table.firstChild); } // Safari doesn't support table.tHead, sigh if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; if (table.tHead.rows.length != 1) return; // can't cope with two header rows // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as // "total" rows, for example). This is B&R, since what you're supposed // to do is put them in a tfoot. So, if there are sortbottom rows, // for backwards compatibility, move them to tfoot (creating it if needed). sortbottomrows = []; for (var i=0; i<table.rows.length; i++) { if (table.rows[i].className.search(//bsortbottom/b/) != -1) { sortbottomrows[sortbottomrows.length] = table.rows[i]; } } if (sortbottomrows) { if (table.tFoot == null) { // table doesn't have a tfoot. Create one. tfo = document.createElement('tfoot'); table.appendChild(tfo); } for (var i=0; i<sortbottomrows.length; i++) { tfo.appendChild(sortbottomrows[i]); } delete sortbottomrows; } // work through each column and calculate its type headrow = table.tHead.rows[0].cells; for (var i=0; i<headrow.length; i++) { // manually override the type with a sorttable_type attribute if (!headrow[i].className.match(//bsorttable_nosort/b/)) { // skip this col mtch = headrow[i].className.match(//bsorttable_([a-z0-9]+)/b/); if (mtch) { override = mtch[1]; } if (mtch && typeof sorttable["sort_"+override] == 'function') { headrow[i].sorttable_sortfunction = sorttable["sort_"+override]; } else { headrow[i].sorttable_sortfunction = sorttable.guessType(table,i); } // make it clickable to sort headrow[i].sorttable_columnindex = i; headrow[i].sorttable_tbody = table.tBodies[0]; dean_addEvent(headrow[i],"click", function(e) { if (this.className.search(//bsorttable_sorted/b/) != -1) { // if we're already sorted by this column, just // reverse the table, which is quicker sorttable.reverse(this.sorttable_tbody); this.className = this.className.replace('sorttable_sorted','sorttable_sorted_reverse'); /* this.removeChild(document.getElementById('sorttable_sortfwdind')); sortrevind = document.createElement('span'); sortrevind.id = "sorttable_sortrevind"; sortrevind.innerHTML = stIsIE ? ' <font face="webdings">5</font>' : ' ▴'; this.appendChild(sortrevind); */ return; } if (this.className.search(//bsorttable_sorted_reverse/b/) != -1) { // if we're already sorted by this column in reverse, just // re-reverse the table, which is quicker sorttable.reverse(this.sorttable_tbody); this.className = this.className.replace('sorttable_sorted_reverse','sorttable_sorted'); /* this.removeChild(document.getElementById('sorttable_sortrevind')); sortfwdind = document.createElement('span'); sortfwdind.id = "sorttable_sortfwdind"; sortfwdind.innerHTML = stIsIE ? ' <font face="webdings">6</font>' : ' ▾'; this.appendChild(sortfwdind); */ return; } // remove sorttable_sorted classes theadrow = this.parentNode; forEach(theadrow.childNodes, function(cell) { if (cell.nodeType == 1) { // an element cell.className = cell.className.replace('sorttable_sorted_reverse',''); cell.className = cell.className.replace('sorttable_sorted',''); } }); /* sortfwdind = document.getElementById('sorttable_sortfwdind'); if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } sortrevind = document.getElementById('sorttable_sortrevind'); if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } */ this.className += ' sorttable_sorted_reverse'; /* sortfwdind = document.createElement('span'); sortfwdind.id = "sorttable_sortfwdind"; sortfwdind.innerHTML = stIsIE ? ' <font face="webdings">6</font>' : ' ▾'; this.appendChild(sortfwdind); */ // build an array to sort. This is a Schwartzian transform thing, // i.e., we "decorate" each row with the actual sort key, // sort based on the sort keys, and then put the rows back in order // which is a lot faster because you only do getInnerText once per row row_array = []; col = this.sorttable_columnindex; rows = this.sorttable_tbody.rows; for (var j=0; j<rows.length; j++) { row_array[row_array.length] = [sorttable.getInnerText(rows[j].cells[col]), rows[j]]; } /* If you want a stable sort, uncomment the following line */ //sorttable.shaker_sort(row_array, this.sorttable_sortfunction); /* and comment out this one */ row_array.sort(this.sorttable_sortfunction); tb = this.sorttable_tbody; for (var j=0; j<row_array.length; j++) { tb.appendChild(row_array[j][1]); } //指定各行css样式 sorttable.changeRowCss(table); delete row_array; }); } } }, //指定各行css样式 changeRowCss:function(table){ var rowclass=table.getAttribute("rowclass"); if(rowclass){ var arr=rowclass.split(","); if(arr.length>0){ rows = table.tBodies[0].rows; for (var j=0; j<rows.length; j++) { var sn=j % (arr.length); rows[j].className=arr[sn]; } } } }, //表头浮动初始化 initScroll: function() { if (!document.createElement || !document.getElementsByTagName) return; forEach(document.getElementsByTagName('table'), function(table) { if (table.className.search(//bscrolltable/b/) != -1) { sorttable.makeScrolltable(table); } }); }, //处理单个表头浮动 makeScrolltable: function(table) { var tablePos=getPosition(table); var theadPos=getPosition(table.tHead.rows[0]); //如果表格可见 if(theadPos.width>0 && theadPos.height>0){ sorttable.scrollRows.push([table.tHead.rows[0],theadPos,tablePos]); } }, /*---------------------------------*/ guessType: function(table, column) { // guess the type of a column based on its first non-blank row sortfn = sorttable.sort_alpha; for (var i=0; i<table.tBodies[0].rows.length; i++) { text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]); if (text != '') { if (text.match(/^-?[$]?[/d,.]+%?$/)) { return sorttable.sort_numeric; } // check for a date: dd/mm/yyyy or dd/mm/yy // can have / or . or - as separator // can be mm/dd as well possdate = text.match(sorttable.DATE_RE) if (possdate) { // looks like a date first = parseInt(possdate[1]); second = parseInt(possdate[2]); if (first > 12) { // definitely dd/mm return sorttable.sort_ddmm; } else if (second > 12) { return sorttable.sort_mmdd; } else { // looks like a date, but we can't tell which, so assume // that it's dd/mm (English imperialism!) and keep looking sortfn = sorttable.sort_ddmm; } } //如果包含中文 else if(/[^/x00-/xff]/g.test(text)){ sortfn = sorttable.sort_gb; } } } return sortfn; }, getInnerText: function(node) { // gets the text we want to use for sorting for a cell. // strips leading and trailing whitespace. // this is *not* a generic getInnerText function; it's special to sorttable. // for example, you can override the cell text with a customkey attribute. // it also gets .value for <input> fields. hasInputs = (typeof node.getElementsByTagName == 'function') && node.getElementsByTagName('input').length; if (node.getAttribute("sorttable_customkey") != null) { return node.getAttribute("sorttable_customkey"); } else if (typeof node.textContent != 'undefined' && !hasInputs) { if(node.textContent=="--"){return "-999999";} return node.textContent.replace(/^/s+|/s+$/g, ''); } else if (typeof node.innerText != 'undefined' && !hasInputs) { if(node.innerText=="--"){return "-999999";} return node.innerText.replace(/^/s+|/s+$/g, ''); } else if (typeof node.text != 'undefined' && !hasInputs) { if(node.text=="--"){return "-999999";} return node.text.replace(/^/s+|/s+$/g, ''); } else { switch (node.nodeType) { case 3: if (node.nodeName.toLowerCase() == 'input') { return node.value.replace(/^/s+|/s+$/g, ''); } case 4: return node.nodeValue.replace(/^/s+|/s+$/g, ''); break; case 1: case 11: var innerText = ''; for (var i = 0; i < node.childNodes.length; i++) { innerText += sorttable.getInnerText(node.childNodes[i]); } return innerText.replace(/^/s+|/s+$/g, ''); break; default: return ''; } } }, reverse: function(tbody) { // reverse the rows in a tbody newrows = []; for (var i=0; i<tbody.rows.length; i++) { newrows[newrows.length] = tbody.rows[i]; } for (var i=newrows.length-1; i>=0; i--) { tbody.appendChild(newrows[i]); } delete newrows; }, /* sort functions each sort function takes two parameters, a and b you are comparing a[0] and b[0] */ sort_numeric: function(a,b) { aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); if (isNaN(aa)) aa = 0; bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); if (isNaN(bb)) bb = 0; return aa-bb; }, sort_alpha: function(a,b) { if (a[0]==b[0]) return 0; if (a[0]<b[0]) return -1; return 1; }, sort_gb:function(a,b){ return a[0].localeCompare(b[0]); }, sort_ddmm: function(a,b) { mtch = a[0].match(sorttable.DATE_RE); y = mtch[3]; m = mtch[2]; d = mtch[1]; if (m.length == 1) m = '0'+m; if (d.length == 1) d = '0'+d; dt1 = y+m+d; mtch = b[0].match(sorttable.DATE_RE); y = mtch[3]; m = mtch[2]; d = mtch[1]; if (m.length == 1) m = '0'+m; if (d.length == 1) d = '0'+d; dt2 = y+m+d; if (dt1==dt2) return 0; if (dt1<dt2) return -1; return 1; }, sort_mmdd: function(a,b) { mtch = a[0].match(sorttable.DATE_RE); y = mtch[3]; d = mtch[2]; m = mtch[1]; if (m.length == 1) m = '0'+m; if (d.length == 1) d = '0'+d; dt1 = y+m+d; mtch = b[0].match(sorttable.DATE_RE); y = mtch[3]; d = mtch[2]; m = mtch[1]; if (m.length == 1) m = '0'+m; if (d.length == 1) d = '0'+d; dt2 = y+m+d; if (dt1==dt2) return 0; if (dt1<dt2) return -1; return 1; }, shaker_sort: function(list, comp_func) { // A stable sort function to allow multi-level sorting of data // see: http://en.wikipedia.org/wiki/Cocktail_sort // thanks to Joseph Nahmias var b = 0; var t = list.length - 1; var swap = true; while(swap) { swap = false; for(var i = b; i < t; ++i) { if ( comp_func(list[i], list[i+1]) > 0 ) { var q = list[i]; list[i] = list[i+1]; list[i+1] = q; swap = true; } } // for t--; if (!swap) break; for(var i = t; i > b; --i) { if ( comp_func(list[i], list[i-1]) < 0 ) { var q = list[i]; list[i] = list[i-1]; list[i-1] = q; swap = true; } } // for b++; } // while(swap) } } /* ****************************************************************** Supporting functions: bundled here to avoid depending on a library ****************************************************************** */ // Dean Edwards/Matthias Miller/John Resig /* for Mozilla/Opera9 */ if (document.addEventListener) { document.addEventListener("DOMContentLoaded", sorttable.init, false); } /* for Internet Explorer */ /*@cc_on @*/ /*@if (@_win32) document.write("<script id=__ie_onload defer src=javascript:void(0)><//script>"); var script = document.getElementById("__ie_onload"); script.onreadystatechange = function() { if (this.readyState == "complete") { sorttable.init(); // call the onload handler } }; /*@end @*/ /* for Safari */ if (/WebKit/i.test(navigator.userAgent)) { // sniff var _timer = setInterval(function() { if (/loaded|complete/.test(document.readyState)) { sorttable.init(); // call the onload handler } }, 10); } /* for other browsers */ window.onload = sorttable.init; // written by Dean Edwards, 2005 // with input from Tino Zijdel, Matthias Miller, Diego Perini // http://dean.edwards.name/weblog/2005/10/add-event/ function dean_addEvent(element, type, handler) { if (element.addEventListener) { element.addEventListener(type, handler, false); } else { // assign each event handler a unique ID if (!handler.$$guid) handler.$$guid = dean_addEvent.guid++; // create a hash table of event types for the element if (!element.events) element.events = {}; // create a hash table of event handlers for each element/event pair var handlers = element.events[type]; if (!handlers) { handlers = element.events[type] = {}; // store the existing event handler (if there is one) if (element["on" + type]) { handlers[0] = element["on" + type]; } } // store the event handler in the hash table handlers[handler.$$guid] = handler; // assign a global event handler to do all the work element["on" + type] = handleEvent; } }; // a counter used to create unique IDs dean_addEvent.guid = 1; function removeEvent(element, type, handler) { if (element.removeEventListener) { element.removeEventListener(type, handler, false); } else { // delete the event handler from the hash table if (element.events && element.events[type]) { delete element.events[type][handler.$$guid]; } } }; function handleEvent(event) { var returnValue = true; // grab the event object (IE uses a global event object) event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event); // get a reference to the hash table of event handlers var handlers = this.events[event.type]; // execute each event handler for (var i in handlers) { this.$$handleEvent = handlers[i]; if (this.$$handleEvent(event) === false) { returnValue = false; } } return returnValue; }; function fixEvent(event) { // add W3C standard event methods event.preventDefault = fixEvent.preventDefault; event.stopPropagation = fixEvent.stopPropagation; return event; }; fixEvent.preventDefault = function() { this.returnValue = false; }; fixEvent.stopPropagation = function() { this.cancelBubble = true; } // Dean's forEach: http://dean.edwards.name/base/forEach.js /* forEach, version 1.0 Copyright 2006, Dean Edwards License: http://www.opensource.org/licenses/mit-license.php */ // array-like enumeration if (!Array.forEach) { // mozilla already supports this Array.forEach = function(array, block, context) { for (var i = 0; i < array.length; i++) { block.call(context, array[i], i, array); } }; } // generic enumeration Function.prototype.forEach = function(object, block, context) { for (var key in object) { if (typeof this.prototype[key] == "undefined") { block.call(context, object[key], key, object); } } }; // character enumeration String.forEach = function(string, block, context) { Array.forEach(string.split(""), function(chr, index) { block.call(context, chr, index, string); }); }; // globally resolve forEach enumeration var forEach = function(object, block, context) { if (object) { var resolve = Object; // default if (object instanceof Function) { // functions have a "length" property resolve = Function; } else if (object.forEach instanceof Function) { // the object implements a custom forEach method so use that object.forEach(block, context); return; } else if (typeof object == "string") { // the object is a string resolve = String; } else if (typeof object.length == "number") { // the object is array-like resolve = Array; } resolve.forEach(object, block, context); } } //获取位置信息 function getPosition(obj) { var top=0; var left=0; var width=obj.offsetWidth; var height=obj.offsetHeight; while (obj.offsetParent) { top += obj.offsetTop; left += obj.offsetLeft; obj = obj.offsetParent; } return {"top":top,"left":left,"width":width,"height":height}; } //表头浮动 function onScroll(){ var scrollRows=sorttable.scrollRows; if(scrollRows.length>0){ for(var i = 0; i < scrollRows.length; i++){ var arr = scrollRows[i]; var pos=arr[1]; //如果表格可见 if(pos.width>0 && pos.height>0){ var top = (document.documentElement && document.documentElement.scrollTop)?document.documentElement.scrollTop : document.body.scrollTop; var maxBottom = arr[1].top+arr[2].height-2*arr[1].height ; if(top<arr[1].top){ arr[0].style.position = "relative"; arr[0].style.top = "0px"; } else if(top >arr[1].top && top < maxBottom){ arr[0].style.position = "absolute"; arr[0].style.top = top+"px"; } } } } } window.onscroll = onScroll;
///////////////////////////////////////////
实现页面内多个表格在滚动时,表头浮动的效果(是同时多个表格哟)
1。为table 的表头所在的tr增加属性:

2。增加样式表(可不添加任何样式):

3。添加js脚本:
1
//
标题栏的自动浮动效果
2
var
oldTop
=
0
;
3
var
trs;
4
var
arrTrs
=
new
Array();
5
function
onScroll()
6
{
7
if (arrTrs && arrTrs.length > 0 )
8
{
9
for ( var i = 0 ; i < arrTrs.length; i ++ )
10
{
11
var arr = arrTrs[i];
12
var top = (document.documentElement && document.documentElement.scrollTop) ?
13
document.documentElement.scrollTop : document.body.scrollTop;
14
if ( (top > arr[ 0 ].offsetTop || arr[ 1 ] < arr[ 0 ].offsetTop) &&
15
top < arr[ 2 ])
16
{
17
arr[ 0 ].style.top = top;
18
}
19
}
20
}
21
}
22
function
load ()
23
{
24
// 获取可浮动表头列表
25
var trs = document.getElementsByClassName( " flowtitle " );
26
if (trs && trs.length > 0 )
27
{
28
for ( var i = 0 ; i < trs.length; i ++ )
29
{
30
var tr = trs[i];
31
tr.style.position = " absolute " ;
32
var arr = new Array( 2 );
33
arr[ 0 ] = tr;
34
arr[ 1 ] = tr.offsetTop; // alert(tr.offsetTop+"|"+tr.parentNode.offsetHeight);
35
arr[ 2 ] = tr.offsetTop + tr.parentNode.offsetHeight;
36
arrTrs[i] = arr;
37
}
38
}
39
}
40
window.onscroll
=
onScroll;
41
window.onload
=
load;

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

29

30

31

32

33

34

35

36

37

38

39

40

41

代码略解:
window.onscroll = onScroll;
window.onload = load; //增加事件
load函数负责初始化可浮动表头对象的列表
load里面的:
arr[0] = tr; //表头对象
arr[1] = tr.offsetTop;// 表头原始位置
arr[2] = tr.offsetTop + tr.parentNode.offsetHeight;//表格底部的位置
tr.style.position = "absolute";//设置表头样式为浮动。 必须!否则不会有任何效果!
onScroll 里面负责处理滚动事件。
if( (top > arr[0].offsetTop || arr[1] < arr[0].offsetTop) &&
top < arr[2])
{
arr[0].style.top = top;
}
//上面这句最重要。判断条件 不明白的话,慢慢琢磨吧
ok,就这么简单。。但效果很酷酷的啦