一个GridView客户端扩展脚本库

近期有个项目频繁使用到GridView控件,于是动手写了个针对GridView的客户端脚本库,用来优化GridView的用户体验,包括行选择(单行选定,多行选定),行点击(单击,双击),行操作(删除,移动)等。兼容包括IE在内的多种内核浏览器。

示例文件下载:https://files.cnblogs.com/wfyfngu/ClientTableDemo.zip

下面是使用该库的一个典型用法。

<!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>
  
<title>ClientTable.js Test</title>
  
<!--引入GridView样式文件-->
  
<link rel="stylesheet" type="text/css" href="/css/grid.css" />
  
<!--ClientTable必须的文件-->
  
<script type="text/javascript" src="/script/RINDEX.js"></script>
  
<script type="text/javascript" src="/script/ClientTable.js"></script>
</head>

<body>

  
<asp:GridView id="gridview1" runat="server">
    
<EmptyDataTemplate>
      
<center>There're no items to show in this view.</center>
    
</EmptyDataTemplate>
  
</asp:GridView>

<script type="text/javascript">
// 实例化一个ClientTable对象
var ETABLE = new ClientTable('gridview1'nullnull);
// 例化一个ClientTable对象,隐藏表格的第一和第二列
//
 var ETABLE = new ClientTable('gridview1', null, [0,1]);
//
 捕捉行选中事件
ETABLE.onSelectChange = function(row) {
 
// 弹出最后一个被选中的行的索引
 alert(row.rowIndex);
};
</script>

</body>

</html>

 

下面附上各个文件的代码。

RINDEX.js


/**
 * @author wfyfngu
 * @create Apri 25, 2008
 
*/


/**
 * @namespace RINDEX
 
*/
if (typeof RINDEX == 'undefined'
    RINDEX 
= {};

/**
 * @namespace RINDEX.Widget
 
*/
if (typeof RINDEX.Widget == 'undefined'
    RINDEX.Widget 
= {};


/**
 * RINDEX 控件公共实用类
 * @class RINDEX.Utility
 * @static
 
*/
RINDEX.Utility 
= {

    
/**
     * 获取一个值,该值指示当前的浏览器是否是IE
     * @field isIE
     * @type Boolean
     
*/
    isIE: document.all 
? true : false,
    
    
/**
     * 获取一个 HTML 元素
     * @method getObject
     * @param obj {HTMLElement || String} 要获取的元素或元素的ID
     * @return HTMLElement
     
*/
    getObject: 
function(obj){
        
if (typeof obj == 'string') {
            
if (this.isIE) 
                obj 
= document.all(obj);
            
else 
                obj 
= document.getElementById(obj);
        }
        
return obj;
    },
    
    
/**
     * 生成具有指定标签的 HTML 元素
     * @method createObject
     * @param tag {String} 要生成的元素的标签
     * @param id {String || Null} 生成的元素的ID
     * @return HTMLElement
     
*/
    createObject: 
function(tag, id){
        
var obj = document.createElement(tag);
        
if (obj) {
            
if (id != null
                obj.id 
= id;
            
return obj;
        }
        
//return document.body;
        return null;
    },
    
    
/**
     * 追加指定的 CSS 样式到目标 HTML 对象
     * @method addCSS
     * @param obj {HTMLElement} 要追加样式的目标对象
     * @param className {String} CSS 样式名称
     * @return void
     
*/
    addCSS: 
function(obj, className){
        
try {
            
var css = obj.className;
            
var index = css.indexOf(className);
            
if (index < 0
                css 
+= ' ' + className;
            
            obj.className 
= css;
        } 
        
catch (e) {
            
// TODO : 删除下一行
            confirm('Exception:' + e);
        }
    },
    
    
/**
     * 从目标 HTML 对象删除指定的 CSS 样式
     * @method addCSS
     * @param obj {HTMLElement} 要删除样式的目标对象
     * @param className {String} CSS 样式名称
     * @return void
     
*/
    removeCSS: 
function(obj, className){
        
try {
            
var css = obj.className;
            
var cssArr = css.split(' ');
            
            
var nwCss = '';
            
            
for (var i = 0; i < cssArr.length; i++) {
                
if (cssArr[i] == className) 
                    
continue;
                nwCss 
+= cssArr[i] + ' ';
            }
            
            obj.className 
= nwCss;
            
        } 
        
catch (e) {
            
// TODO : 删除下一行
            confirm('Exception:' + e);
        }
    },
    
    
/**
     * 使用指定的数值格式化表格
     * @method formatTable
     * @param tableObject {HtmlTableElement} 要格式化的表格
     * @param border {Number} 表格的边框宽度
     * @param cellSpacing {Number} 表格单元格的间距
     * @param cellPadding {Number} 表格中单元格的边距
     * @param align {String} 表格的对齐方式
     * @return void
     
*/
    formatTable: 
function(tableObject, border, cellSpacing, cellPadding, align){
        
if (border == null || isNaN(parseInt(border))) 
            border 
= 0;
        
else 
            border 
= parseInt(border);
        
        
if (cellSpacing == null || isNaN(parseInt(cellSpacing))) 
            cellSpacing 
= 0;
        
else 
            cellSpacing 
= parseInt(border);
        
        
if (cellPadding == null || isNaN(parseInt(cellPadding))) 
            cellPadding 
= 0;
        
else 
            cellPadding 
= parseInt(border);
        
        tableObject.border 
= border;
        tableObject.cellPadding 
= cellSpacing;
        tableObject.cellSpacing 
= cellPadding;
        
if (align) 
            tableObject.align 
= align;
    },
    
    
/**
     * 还原因单击,双击或其它交互引起的任何控件格式的改变
     * 通常运用于FireFox等非IE内核的浏览器
     * @method refreshControl
     * @return void
     
*/
    refreshControl: 
function(){
        
var sel;
        
if (window.getSelection) {
            sel 
= window.getSelection();
        }
        
else 
            
if (document.getSelection) {
                sel 
= document.getSelection();
            }
            
else 
                
if (document.selection) {
                    sel 
= document.selection;
                }
        
        
if (sel) {
            
if (sel.empty) {
                sel.empty();
            }
            
else 
                
if (sel.removeAllRanges) {
                    sel.removeAllRanges();
                }
                
else 
                    
if (sel.collapse) {
                        sel.collapse();
                    }
        }
    },
    
    
/**
     * @method toString
     * @return String
     
*/
    toString: 
function(){
        
return '[Object:RINDEX.Utility]';
    }
    
};

/*==============================================================================================*/

/**
 * @class RINDEX.Lang
 * @static
 
*/
RINDEX.Lang 
= {
    
    
/**
     * 检查指定的对象是否是数组
     * @param {Object} input 要检查的对象
     * @return Boolean
     
*/
    isArray : 
function(input) {
        
if (input && input.slice &&input.push)
            
return true;
        
return false;
    },
    
    
/**
     * 检查指定的对象是否是数字
     * @param {Object} input 要检查的对象
     * @return Boolean
     
*/
    isNumber : 
function(input) {
        
return typeof input == 'number' && isFinite(input);
    },
    
    
/**
     * 从父类复制方法到指定的子类
     * @param subClass {Function}  子类
     * @param superClass {Function} 父类
     
*/
    extend : 
function(subClass, superClass) {
        
if (!subClass||!superClass) {
            
throw new Error("Call RINDEX.Lang.extend failed, not all arguments are included.");
        }
        
var F = function() {};
        F.prototype
=superClass.prototype;
        subClass.prototype
=new F();
        subClass.prototype.constructor
=subClass;
        subClass.superclass
=superClass.prototype;
        
if (superClass.prototype.constructor == Object.prototype.constructor) {
            superClass.prototype.constructor
=superClass;
        }
    },
    
    
/**
     * @private
     
*/
    toString : 
function() {
        
return '[RINDEX.Lang]';
    }

    
};

/*==============================================================================================*/

/**
 * 可以用来表示一个平面坐标中某一特定位置的类
 * @class RINDEX.Position
 * @param {number} x X坐标
 * @param {number} y Y坐标
 
*/
RINDEX.Position 
= function(x,y) {
    
    
/**
     * X坐标
     * @field x
     * @type Number
     
*/
    
this.x = x;
    
    
/**
     * Y坐标
     * @field y
     * @type Number
     
*/
    
this.y = y;
    
    
if(!RINDEX.Lang.isNumber(this.x))
        
this.x = 0;
    
if(!RINDEX.Lang.isNumber(this.y))
        
this.y = 0;
        
};

 

ClientTable.js

// JScript File

if(typeof RINDEX == 'undefined' || typeof RINDEX.Widget == 'undefined')
    
throw new Error('Required file "RIndex.js" was missing.');

ClientTable 
= function(tableToConvert, excludeRowClassNameArr, hiddenColumnIndexArr) {
  
  
this.table = RINDEX.Utility.getObject(tableToConvert);
    
    
this.selectedRows = [];
    
    
this.disabled = false;
    
    
/**
     * @field multiSelection
     * 获取一个值,该值指示是否可以同时选中多行
     *@type Boolean
     
*/
    
this.multiSelection = true;
    
    
this.excludeClassName = excludeRowClassNameArr;
    
this.hiddenColumnIndex = hiddenColumnIndexArr; // 要隐藏的列

    
if(this.table != null) {
      
this.table.onselectstart = function() {return false;};
      RINDEX.Utility.formatTable(
this.table);
      RINDEX.Utility.addCSS(
this.table,'editTable');
      
this._init();
    }
  
};


ClientTable.prototype 
= {

  
// Events
  onRowSelected : function(row) {
        
return true;
    },
    
  onSelectChange : 
function(row) {
        
return true;
    },
    
    onDblClick : 
function(row) {
        
return true;
    },

  _init : 
function() {
    
this._format();
    
if(!this.disabled) {
      
this._attachEvent();
    }
  },
  
  _format : 
function() {
    
if(this.table.rules)
      
this.table.rules = 'none';
    
var rowCount = this.table.rows.length;
    
var cellCount = null;
    
var tblHeader, tblRow;
    
    
// Hide the haeder row
    tblHeader = this.table.rows[0];
    
if(0 in tblHeader.cells) {
      
if(tblHeader.cells[0].tagName.toUpperCase() == 'TH') {
        
this._hidColume(this.table.rows[0]);
      }
    }
    
    
// Hide all other rows
    for(var i=1; i<rowCount; i++) {
      tblRow 
= this.table.rows[i];
      
this._hidColume(tblRow);
      
      
if(this._skipRow(tblRow))
        
continue;
      
if(cellCount == null) {
        cellCount 
= tblRow.cells.length;
      }
      
for(var cell=0; cell<cellCount; cell++){
        tblRow.cells[cell].className 
= 'item-' + ((i+1)%2);
      }
    }
  },
  
  _hidColume : 
function(rowEL) {
    
if(this.hiddenColumnIndex && this.hiddenColumnIndex.length) {
      
var indexCount = this.hiddenColumnIndex.length;
      
if(indexCount>0) {
      
        
if(this._skipRow(rowEL)) {
          rowEL.childNodes[
0].colSpan -= indexCount;
        } 
else {
          
for(var cell=0; cell<rowEL.cells.length; cell++) {
            
for(var index=0; index<indexCount; index++){
              
if(this.hiddenColumnIndex[index] == cell) {
                rowEL.cells[cell].style.display 
= 'none';
              }
            }
          }
        }
        
      }
    }
  },
  
  _attachEvent : 
function(event) {
    
var rowCount = this.table.rows.length;
    
var tblRow; var self = this;
    event 
= event || window.event;
    
for(var i=1; i<rowCount; i++) {
      tblRow 
= this.table.rows[i];
      
if(this._skipRow(tblRow))
        
continue;
      tblRow.onclick 
= function(event) {
        self.select(
this, event);
      };
      tblRow.ondblclick 
= function() {
        self.onDblClick(
this);
      };
    } 
  },
  
  _skipRow : 
function(rowEL) {
    
if(rowEL.className && this.excludeClassName && this.excludeClassName.length) {
      
for(var i=0; i<this.excludeClassName.length; i++) {
        
if(this.excludeClassName == rowEL.className)
          
return true;
      }
    }
    
return false;
  },
  
  select : 
function(row, event) {
    
        event 
= event || window.event;
            
        
if(RINDEX.Lang.isNumber(row))
            row 
= this.table.rows[row];
            
        
if(this.multiSelection == false) {
        
          
if(this.selectedRows.length > 0) {
            
if(this.selectedRows[0!= row) {
              
this.unSelect(this.selectedRows[0]);
              
this.selectedRows = [row];
              
this._appendSelectStyle(row);
              
this.onRowSelected(row);
                    
this.onSelectChange(row);
            }
          } 
else {
            
this.selectedRows = [row];
            
this._appendSelectStyle(row);
            
this.onRowSelected(row);
                
this.onSelectChange(row);
          }
        }
        
        
else {
            
            
var contains = false;
            
for(var i=0; i<this.selectedRows.length; i++) {
                
if(this.selectedRows[i] == row) {
                    contains 
= true;
                    
break;
                }
            }

            
if(event.ctrlKey) {
                
                
if(!contains) {
                    
this.selectedRows.push(row);
                    
this._appendSelectStyle(row);
                    
this.onRowSelected(row);
                    
this.onSelectChange(row);
                } 
else {
                    
this.unSelect(row);
                }
            }
            
            
else if(event.shiftKey) {
            
              
var baseRow = 0;
              
if(this.selectedRows.length > 0)
                baseRow 
= this.selectedRows[this.selectedRows.length-1].rowIndex
                
              
var nwArr = [];
              
var rowIndex = row.rowIndex;
              
              
if(baseRow < rowIndex) {
                    
for(var value = rowIndex; value>=baseRow; value--) {
                            nwArr.push(value);
                    }
                } 
else {
                    
for(var value = rowIndex; value<=baseRow; value++) {
                            nwArr.push(value);
                    }
                }

                
this._clearAllSelection();
                
                
for(var i=0; i<nwArr.length; i++) {
                  
this.selectedRows.push(this.table.rows[nwArr[i]]);
                  
this._appendSelectStyle(this.table.rows[nwArr[i]]);
                }
                
                
this.onSelectChange(row);
                
            }
            
            
else {
                
                
this._clearAllSelection();
                
                
this.selectedRows.push(row);
                
this._appendSelectStyle(row);
                
this.onRowSelected(row);
                
this.onSelectChange(row);
            }
            
        }
        
        RINDEX.Utility.refreshControl();
        
    },
    
    unSelect : 
function(row) {
      
if(this.disabled) return row;
        
if(RINDEX.Lang.isNumber(row))
            row 
= this.table.rows[row];
            
        
var index = -1;
        
for(var i=0; i<this.selectedRows.length; i++) {
            
if(this.selectedRows[i] == row) {
                index 
= i;
                
break;
            }
        }
        
        
if(index > -1) {
            
this.selectedRows =
                
this.selectedRows.slice(0,index).concat(this.selectedRows.slice(index+1));
            
this._clearSelectStyle(row);
            
this.onSelectChange(row);
        }
            
    },
    
    moveUp : 
function(rowEL) { 
      
var currentRowIndex = rowEL.rowIndex;
      
if(currentRowIndex<2)
        
return;
      
var nwRow = this.table.insertRow(currentRowIndex-1);
      
var tempCell, rawCell;
      
for(var i=0; i<rowEL.cells.length; i++) {
        rawCell 
= rowEL.cells[i];
        tempCell 
= nwRow.insertCell(i);
        tempCell.innerHTML 
= rawCell.innerHTML;
        tempCell.className 
= rawCell.className;
      }
      
this.remove(rowEL);
      
this._attachEvent();
      
this.select(nwRow);
    },
    
    moveDown : 
function(rowEL) {
      
var currentRowIndex = rowEL.rowIndex;
      
if(currentRowIndex==this.table.rows.length-1)
        
return;
      
var nwRow = this.table.insertRow(currentRowIndex+2);
      
var tempCell, rawCell;
      
for(var i=0; i<rowEL.cells.length; i++) {
        rawCell 
= rowEL.cells[i];
        tempCell 
= nwRow.insertCell(i);
        tempCell.innerHTML 
= rawCell.innerHTML;
        tempCell.className 
= rawCell.className;
      }
      
this.remove(rowEL);
      
this._attachEvent();
      
this.select(nwRow);
    },
    
    remove : 
function(row) {
      
if(this.disabled) return row;
        
if(RINDEX.Lang.isNumber(row))
            row 
= this.table.rows[row];
        
try {
            
this.unSelect(row);
            
this.table.deleteRow(row.rowIndex);
            
this._format();
        } 
catch(e) {
            
//
        }
    },
    
    removeSelectedRows : 
function() {
      
if(this.disabled) return;
        
while(this.selectedRows.length > 0)
            
this.remove(this.selectedRows[0]);
    },
    
    getCellText : 
function(cellIndex) {
      
var rowCount = this.selectedRows.length;
      
var arr = new Array(rowCount);
      
for(var i=0; i<rowCount; i++) {
        
if(document.all)
          arr[i] 
= this.selectedRows[i].cells[cellIndex].innerText;
        
else
          arr[i] 
= this.selectedRows[i].cells[cellIndex].textContent;
      }
      
return arr;
    },
    
    changeHeaderText : 
function(textArr) {
      
var headerRow = this.table.rows[0];
      
var cellCount = headerRow.cells.length-1;
      
var tempCellEL;
      
for(var i=0; i<textArr.length; i++) {
        
if(i > cellCount)
          
continue;
        tempCellEL 
= headerRow.cells[i];
        
if(tempCellEL.tagName.toUpperCase() == 'TH') {
          tempCellEL.innerHTML 
= textArr[i];
        }
      }
    },
    
    _appendSelectStyle : 
function(row) {
        
        
for(var cell=0; cell<row.cells.length; cell++) {
            RINDEX.Utility.addCSS(row.cells[cell], 
'selected');
        }
        
    },
    
    _clearSelectStyle : 
function(row) {
        
        
for(var cell=0; cell<row.cells.length; cell++) {
            RINDEX.Utility.removeCSS(row.cells[cell], 
'selected');
        }
        
    },
    
    _clearAllSelection : 
function() {
        
for(var i=0; i<this.selectedRows.length; i++) {
            
this._clearSelectStyle(this.selectedRows[i]);
        }
        
this.selectedRows.length = 0;
    },

  toString : 
function() {
    
return '[ClientTable]';
  }

};

 

grid.css

.editTable {
    border-collapse
:collapse;
    cursor
: default;
    width
: 100%;
    empty-cells
: show;
}

.editTable th,
.editTable td 
{
    font-size
: 12px;
    padding
: 3px 5px;
}

.editTable th 
{
    text-align
: left;
    font-weight
: bold;
    line-height
: 20px;
    height
: 20px;
    background-color
: #f5fafa;
    border-right
: 1px solid #C1DAD7;
    border-bottom
: 1px solid #C1DAD7;
    border-left
: 1px solid #C1DAD7;
    
/*border-color: #FFF #C1DAD7 #C1DAD7 #FFF;*/
    white-space
: nowrap;
}

.editTable td.item-0,
.editTable td.item-1 
{
    border-bottom
: 1px solid #ccc;
    
/*text-align: left;*/
}

.editTable td.item-0 
{
    background-color
: #fff;
    color
: #555;
    empty-cells
: show;
    font-family
: "Lucida Sans Unicode", "Lucida Sans",  "Trebuchet MS", Verdana, Tahoma;
}

.editTable td.item-1 
{
    background-color
: #F5FAFA;
    color
: #555;
    empty-cells
: show;
    font-family
:  "Lucida Sans Unicode", "Lucida Sans",  "Trebuchet MS", Verdana, Tahoma;
}

.editTable td.selected 
{
    color
: #fff;
    background-color
: #ff8c00;
}

table tr.tfooter
{
    background-color
: ButtonFace;
    border
: 1px solid;
    border-color
: buttonhighlight buttonshadow buttonshadow buttonhighlight;
}

table tr.tfooter td 
{
    text-align
: right;
}
posted @ 2009-02-01 13:02  wfyfngu  阅读(2377)  评论(0编辑  收藏  举报
方糖网