JS版本表格排序 [ Table Sort ]
于 08-02-28 12:28 通过网页 帖子号: 14194
关键字: Array对象, sort(), DOM
Array用于在单独变量名中存放一系列的值.
对Array对象常用的方法 [ 行为 ] 有: concat(), join(), pop(), push(), reverse(), shift(), slice(), sort(), splice(), toString()等.
在这个话题中会选用Array.sort()这个方法作为主要原理, 辅以reverse()进行倒序控制.
数字排序
sort()方法默认是按照数组单元的ASCII字符码进行排列, 也就是说不适合我们一般意义上的数字排序.
var arr = [1,15,35,10,5];
arr.sort();
alert(arr.toString());
输出的会是: 1, 10, 15, 35, 5, 这时,就要用到sort()方法中可以接受的一个参数 - 比较函数.
这个比较函数返回3种状态: 进行比较的值之间是大于, 小于还是等于.
这个函数可能会是这样:
function comparison(value1, value2){
if(value1 < value2){
return -1;
}else if(value1 > value2){
return 1;
}else{
return 0;
}
}
调用的时候使用:
arr.sort(comparison);
更进一步, 我们对传入的两个参数进行控制, 把传入的参数转换成数字:
function comparison(value1, value2){
var iNum1 = parseInt(value1);
var iNum2 = parseInt(value2);
if(iNum1 < iNum2){
return -1;
}else if(iNum1 > iNum2){
return 1;
}else{
return 0;
}
}
字符排序
那么更简单的, 调用String对象中的LocaleCompare()方法即可完成对字符和数字的比较.
reverse()方法
简单地说, 就是将数组中元素的顺序倒转.
step - 1 入门: 单列表格的排序
表格结构:
<table cellspacing="0" id="needSort">
<caption>User End Design</caption>
<thead>
<tr>
<th scope="col">Type</th>
</tr>
</thead>
<tbody>
<tr>
<td>Graphic Design</td>
</tr>
<tr>
<td>(X)HTML</td>
</tr>
<tr>
<td>CSS</td>
</tr>
<tr>
<td>JavaScript</td>
</tr>
</tbody>
</table>
示意代码如上, 注意要将表头行和数据行分离, 使用表格的 tBodies 元素组获取表格中tbody元素及它所有的子元素.
比较函数:
function comparison(tr1, tr2){
var value1= tr1.cells[0].firstChild.nodeValue;
var value2= tr2.cells[0].firstChild.nodeValue;
return value1.localeCompare(value2);
}
这个函数是根据每行第一个单元格的值进行排序
排序函数:
Step 1:
function tableSort(id){
var _table = document.getElementById(id);
var _tbody = _table.tBodies[0];
var _dataGrids = _tbody.rows;
}
这里对需要进行处理的数据所在的容器做了定位,rows是DOM集合, 并不是像它表现出来的数组形式. 所以它没有sort()方法.我们要做的是要自己构建一个代表rows的数组.
step 2:
function tableSort(id){
var _table = document.getElementById(id);
var _tbody = _table.tBodies[0];
var _dataGrids = _tbody.rows;
var _trow = new Array();
for(var i=0; i<_dataGrids.length; i++){
_trow.push(_dataGrids[i]);
}
_trow.sort(comparison);
}
这里把所有的tr对象都存入_trow数组中,然后对_trow数组应用sort()方法. 在数组中, 元素已经排列好了, 剩下的事情就是处理页面显示了.
我们可以直接用 _tbody.appendChild 来循环修改表格, 也可以通过创建文档片段来一次性修改.
function tableSort(id){
var _table = document.getElementById(id);
var _tbody = _table.tBodies[0];
var _dataGrids = _tbody.rows;
var _trow = new Array();for(var i=0; i<_dataGrids.length; i++){
_trow.push(_dataGrids[i]);
}_trow.sort(comparison);
//var _fragment = document.createDocumentFragment();
for(var i=0;i<_trow.length;i++){
//_fragment.appendChild(_trow[i]);
_tbody.appendChild(_trow[i]);
}
//_tbody.appendChild(_fragment);
}
蓝色部分代码是循环修改, 红色部分代码是创建文档片段一次性创建.
剩下来的事情就是绑定用户行为了,
<table cellspacing="0" id="needSort" border="1">
<caption>User End Design</caption>
<thead>
<tr>
<th scope="col" onclick="tableSort('needSort')">Type</th>
</tr>
</thead>
......
这里有悖于无侵入编程的原则, 唔, 不爽, 先留着慢慢改. 在可以通过定义CSS来给thead / tr / th 添加鼠标样式: cursor:pointer .
楼主
于 08-02-28 15:56 通过网页
单列表格的例子完毕, 很简单不是吗? 但是在实际应用中, 很少会遇到单列表格吧... 那我们也要进一步了.
<table cellspacing="0" id="needSort" class="needSort">
<caption>User End Design</caption>
<thead>
<tr>
<th scope="col">Type</th>
<th scope="col">Editor</th>
</tr>
</thead>
<tbody>
<tr>
<td>Graphic Design</td>
<td>Photoshop</td>
</tr>
<tr>
<td>(X)HTML</td>
<td>DreamWeaver</td>
</tr>
<tr>
<td>CSS</td>
<td>StyleTop</td>
</tr>
<tr>
<td>JavaScript</td>
<td>EditPlus</td>
</tr>
</tbody>
</table>
之前的比较函数限制较多, 现在通过传递参数的方法打开限制.
function generateCompare(ind){
return function comparison(tr1, tr2){
var value1= tr1.cells[ind].firstChild.nodeValue;
var value2= tr2.cells[ind].firstChild.nodeValue;
return value1.localeCompare(value2);
}
}
这样就能对任意列的数据进行比较了. 只需要一个表列的索引即可.
恩,构建一个无侵入的脚本吧.
var _table = document.getElementsByTagName("table");
for(var i=0;i<_table.length;i++){
if(_table[i].className){
if(_table[i].className=="needSort"){
var _thead = _table[i].getElementsByTagName("thead")[0];
var _tr = _thead.rows[0];
var _th = _tr.cells;
for(var j=0;j<_th.length;j++){
_th[j].onclick = tableSort;
}
}
}
}
所有定义了 class="needSort" 的table都可以调用这段代码了.
我们再来看tableSort 这个函数:
function tableSort(ev){
var ev = ev || window.event;
var _target = ev.target || ev.srcElement;
var _parent = _target.parentNode;
var _children = new Array();
var _tableCur = _parent.parentNode.parentNode;
var _tbody = _tableCur.tBodies[0];
var _cellGrids;
for(var i=0;i<_parent.childNodes.length;i++){
if(_parent.childNodes[i].nodeType=="1"){
_children.push(_parent.childNodes[i]);
}
}
for(var i=0;i<_children.length;i++){
if(_target==_children[i]){
_cellGrids = getColumnArray(i,_tableCur);
var _fragment = document.createDocumentFragment();
for(var j=0;j<_cellGrids.length;j++){
_fragment.appendChild(_cellGrids[j])
}
_tbody.appendChild(_fragment)
}else{
continue;
}
}
}
标识出2块代码段, 这两块代码段都是为兼容IE和Firefox准备的, Firefox中没有window.event事件, IE中没有把硬回车算成一个节点. Firefox和IE的兼容问题...有空再整理. 这里就先带过了.
其中我把组成列数组的部分单独提出来作为一个函数, 只是为了看上去清楚一点...
function getColumnArray(ind,tab){
var _tbody = tab.tBodies[0];
var dataGrids = _tbody.rows;
var _trow = new Array();
for(var i=0; i<dataGrids.length; i++){
_trow.push(dataGrids[i]);
}
_trow.sort(generateCompare(ind));
return _trow;
}
这样一个多列表格的排序也完成了. 唔, 离我们的目标更近了一步.
1楼
于 08-02-28 16:45 通过网页
这部分就非常简单了, 只要用到Array对象的reverse()方法就基本搞定了.
修改过的函数有2个:
function getColumnArray(ind,tab,obj){
var _tbody = tab.tBodies[0];
var dataGrids = _tbody.rows;
var _trow = new Array();
for(var i=0; i<dataGrids.length; i++){
_trow.push(dataGrids[i]);
}
if(obj.sortType && obj.sortType=="asc"){
_trow.reverse();
}else{
_trow.sort(generateCompare(ind))
}
return _trow;
}function tableSort(ev){
var ev = ev || window.event;
var _target = ev.target || ev.srcElement;
var _parent = _target.parentNode;
var _children = new Array();
var _tableCur = _parent.parentNode.parentNode;
var _tbody = _tableCur.tBodies[0];
var _cellGrids;
for(var i=0;i<_parent.childNodes.length;i++){
if(_parent.childNodes[i].nodeType=="1"){
_children.push(_parent.childNodes[i]);
}
}
for(var i=0;i<_children.length;i++){
if(_target==_children[i]){
_cellGrids = getColumnArray(i,_tableCur,_target);
var _fragment = document.createDocumentFragment();
for(var j=0;j<_cellGrids.length;j++){
_fragment.appendChild(_cellGrids[j]);
}
_tbody.appendChild(_fragment);
_target.sortType = "asc";
}else{
continue;
}
}
}
通过给触发排序的元素th增加一个sortType的属性来标识其是否已经经过排序, 关键字可以随便取...反正是字符串.能匹配上就成.
然后在生成数组并排序的地方进行判断, 已经排序的就用倒序呈现, 没有经过排序的, 就进行正常排序.
2楼
于 08-02-28 17:02 通过网页
还真是方便啊方便是挺方便的,但是JS对大型DOM Tree操作还是有点困难...
4楼