基於jQuery的TreeGrid組件
/** * @author 陳舉民 * @version 1.0 * @link http://chenjumin.iteye.com/blog/419522 */ TreeGrid = function (_config) { _config = _config || {}; var s = ""; var rownum = 0; var __root; var __selectedData = null; var __selectedId = null; var __selectedIndex = null; var folderOpenIcon = (_config.folderOpenIcon || TreeGrid.FOLDER_OPEN_ICON); var folderCloseIcon = (_config.folderCloseIcon || TreeGrid.FOLDER_CLOSE_ICON); var defaultLeafIcon = (_config.defaultLeafIcon || TreeGrid.DEFAULT_LEAF_ICON); //顯示錶頭行 drowHeader = function () { s += "<tr class='header' height='" + (_config.headerHeight || "25") + "'>"; var cols = _config.columns; for (i = 0; i < cols.length; i++) { var col = cols[i]; s += "<td align='" + (col.headerAlign || _config.headerAlign || "center") + "' width='" + (col.width || "") + "'>" + (col.headerText || "") + "</td>"; } s += "</tr>"; } //遞歸顯示數據行 drowData = function () { var rows = _config.data; var cols = _config.columns; drowRowData(rows, cols, 1, ""); } //局部變量i、j必須要用 var 來聲明,否則,後續的數據無法正常顯示 drowRowData = function (_rows, _cols, _level, _pid) { var folderColumnIndex = (_config.folderColumnIndex || 0); for (var i = 0; i < _rows.length; i++) { var id = _pid + "_" + i; //行id var row = _rows[i]; s += "<tr id='TR" + id + "' data-pid='" + ((_pid == "") ? "0" : ("TR" + _pid)) + "' data-open='Y' data-row=\"" + TreeGrid.json2str(row) + "\" data-rowIndex='" + rownum++ + "'>"; for (var j = 0; j < _cols.length; j++) { var col = _cols[j]; s += "<td align='" + (col.dataAlign || _config.dataAlign || "left") + "'"; //層次縮進 if (j == folderColumnIndex) { s += " style='text-indent:" + (parseInt((_config.indentation || "20")) * (_level - 1)) + "px;'> "; } else { s += ">"; } //節點圖標 if (j == folderColumnIndex) { if (row.children) { //有下級數據 s += "<img data-folder='Y' data-trid='TR" + id + "' src='" + folderOpenIcon + "' class='image_hand'>"; } else { s += "<img src='" + defaultLeafIcon + "' class='image_nohand'>"; } } //單元格內容 if (col.handler) { s += (eval(col.handler + ".call(new Object(), row, col)") || "") + "</td>"; } else { s += (row[col.dataField] || "") + "</td>"; } } s += "</tr>"; //遞歸顯示下級數據 if (row.children) { drowRowData(row.children, _cols, _level + 1, id); } } } //主函數 this.show = function () { this.id = _config.id || ("TreeGrid" + TreeGrid.COUNT++); s += "<table id='" + this.id + "' cellspacing=0 cellpadding=0 width='" + (_config.width || "100%") + "' class='TreeGrid'>"; drowHeader(); drowData(); s += "</table>"; __root = jQuery("#" + _config.renderTo); __root.append(s); //初始化動作 init(); } init = function () { //以新背景色標識鼠標所指行 if ((_config.hoverRowBackground || "false") == "true") { __root.find("tr").hover( function () { if (jQuery(this).attr("class") && jQuery(this).attr("class") == "header") return; jQuery(this).addClass("row_hover"); }, function () { jQuery(this).removeClass("row_hover"); } ); } //將單擊事件綁定到tr標籤 __root.find("tr").bind("click", function () { __root.find("tr").removeClass("row_active"); jQuery(this).addClass("row_active"); //獲取當前行的數據 __selectedData = jQuery(this).attr('data-row'); __selectedId = jQuery(this).attr('id'); __selectedIndex = jQuery(this).attr('data-rowIndex'); //行記錄單擊後觸發的事件 if (_config.itemClick) { eval(_config.itemClick + "(__selectedId, __selectedIndex, TreeGrid.str2json(__selectedData))"); } }); //展開、關閉下級節點 __root.find("img[data-folder='Y']").bind("click", function () { var trid = jQuery(this).attr("data-trid"); var isOpen = __root.find("#" + trid).attr("data-open"); isOpen = (isOpen == "Y") ? "N" : "Y"; __root.find("#" + trid).attr("data-open", isOpen); showHiddenNode(trid, isOpen); }); } //顯示或隱藏子節點數據 showHiddenNode = function (_trid, _open) { if (_open == "N") { //隱藏子節點 __root.find("#" + _trid).find("img[data-folder='Y']").attr("src", folderCloseIcon); __root.find("tr[id^=" + _trid + "_]").css("display", "none"); } else { //顯示子節點 __root.find("#" + _trid).find("img[data-folder='Y']").attr("src", folderOpenIcon); showSubs(_trid); } } //遞歸檢查下一級節點是否需要顯示 showSubs = function (_trid) { var isOpen = __root.find("#" + _trid).attr("data-open"); if (isOpen == "Y") { var trs = __root.find("tr[data-pid=" + _trid + "]"); trs.css("display", ""); for (var i = 0; i < trs.length; i++) { showSubs(trs[i].id); } } } //展開或收起所有節點 this.expandAll = function (isOpen) { var trs = __root.find("tr[data-pid='0']"); for (var i = 0; i < trs.length; i++) { var trid = trs[i].id || trs[i].getAttribute("id"); showHiddenNode(trid, isOpen); } } //取得當前選中的行記錄 this.getSelectedItem = function () { return new TreeGridItem(__root, __selectedId, __selectedIndex, TreeGrid.str2json(__selectedData)); } }; //公共靜態變量 TreeGrid.FOLDER_OPEN_ICON = "images/folderOpen.gif"; TreeGrid.FOLDER_CLOSE_ICON = "images/folderClose.gif"; TreeGrid.DEFAULT_LEAF_ICON = "images/defaultLeaf.gif"; TreeGrid.COUNT = 1; //將json對象轉換成字符串 TreeGrid.json2str = function(obj){ var arr = []; var fmt = function(s){ if(typeof s == 'object' && s != null){ if(s.length){ var _substr = ""; for(var x=0;x<s.length;x++){ if(x>0) _substr += ", "; _substr += TreeGrid.json2str(s[x]); } return "[" + _substr + "]"; }else{ return TreeGrid.json2str(s); } } return /^(string|number)$/.test(typeof s) ? "'" + s + "'" : s; } for(var i in obj){ if(typeof obj[i] != 'object'){ //暫時不包括子數據 arr.push(i + ":" + fmt(obj[i])); } } return '{' + arr.join(', ') + '}'; } TreeGrid.str2json = function(s){ var json = null; if(jQuery.browser.msie){ json = eval("(" + s + ")"); }else{ json = new Function("return " + s)(); } return json; } //數據行對象 function TreeGridItem (_root, _rowId, _rowIndex, _rowData){ var __root = _root; this.id = _rowId; this.index = _rowIndex; this.data = _rowData; this.getParent = function(){ var pid = jQuery("#" + this.id).attr("data-pid"); if(pid!=""){ var rowIndex = jQuery("#" + pid).attr("data-rowIndex"); var data = jQuery("#" + pid).attr("data-row"); return new TreeGridItem(_root, pid, rowIndex, TreeGrid.str2json(data)); } return null; } this.getChildren = function(){ var arr = []; var trs = jQuery(__root).find("tr[data-pid='" + this.id + "']"); for(var i=0;i<trs.length;i++){ var tr = trs[i]; arr.push(new TreeGridItem(__root, tr.id, tr.rowIndex, TreeGrid.str2json(tr.data))); } return arr; } };
body{ font-size:11px; } .TreeGrid{ border-collapse: collapse; font-size: 11px; border: 1px solid #778899; } .TreeGrid .header{ background-color: #87CEEB; font-size: 11px; font-weight: 600; } .TreeGrid td{ border: 1px solid #E6E6FA; padding: 4px 3px 2px 3px; } .TreeGrid a{ text-decoration: underline; color: black; } .TreeGrid a:hover{ color: blue; } .TreeGrid .image_hand{ border: 0; cursor:hand; align:absmiddle; } .TreeGrid .image_nohand{ border: 0; align:absmiddle; } .TreeGrid .row_hover{ background-color: #E6E6FA; } .TreeGrid .row_active{ background-color: #E0FFFF; }
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <link href="css/treeGrid/TreeGrid.css" rel="stylesheet" type="text/css" /> <script src="js/jquery.min.js" type="text/javascript"></script> <script src="js/TreeGrid.js" type="text/javascript"></script>
<script src="js/index.js" type="text/javascript"></script></head><body> <div id="div1"> </div> <input type="button" value="關閉所有節點" onclick="expandAll('N')"> <input type="button" value="展開所有節點" onclick="expandAll('Y')"> <input type="button" value="取得當前行的數據" onclick="selectedItem()"><br> 當前選中的行: <input type="text" id="currentRow" size="110" /></body></html>
index.js代碼如下:
$(document).ready(function(){
var config = {
id: "tg1",
width: "800",
renderTo: "div1",
headerAlign: "left",
headerHeight: "30",
dataAlign: "left",
indentation: "20",
folderOpenIcon: "images/folderOpen.gif",
folderCloseIcon: "images/folderClose.gif",
defaultLeafIcon: "images/defaultLeaf.gif",
hoverRowBackground: "false",
folderColumnIndex: "1",
itemClick: "itemClickEvent",
columns: [
{ headerText: "", headerAlign: "center", dataAlign: "center", width: "20", handler: "customCheckBox" },
// {headerText: "", headerAlign: "center", dataAlign: "center", width: "20" },
{ headerText: "名稱", dataField: "name", headerAlign: "center", handler: "customOrgName" },
{ headerText: "拼音碼", dataField: "code", headerAlign: "center", dataAlign: "center", width: "100" },
{ headerText: "負責人", dataField: "assignee", headerAlign: "center", dataAlign: "center", width: "100" }
],
data: [
{ name: "城區分公司", code: "CQ", assignee: "", children: [
{ name: "城區卡品分銷中心" },
{ name: "先鋒服務廳", children: [
{ name: "chlid1" },
{ name: "chlid2" },
{ name: "chlid3", children: [
{ name: "chlid3-1" },
{ name: "chlid3-2" },
{ name: "chlid3-3" },
{ name: "chlid3-4" }
]
}
]
},
{ name: "半環服務廳" }
]
},
{ name: "清新分公司", code: "QX", assignee: "", children: [] },
{ name: "英德分公司", code: "YD", assignee: "", children: [] },
{ name: "佛岡分公司", code: "FG", assignee: "", children: [] }
]
};
//創建一個組件對象
treeGrid = new TreeGrid(config);
treeGrid.show();
});
var treeGrid;
/*
單擊數據行後觸發該事件
id:行的id
index:行的索引。
data:json格式的行數據對象。
*/
function itemClickEvent(id, index, data) {
jQuery("#currentRow").val(id + ", " + index + ", " + TreeGrid.json2str(data));
}
/*
通過指定的方法來自定義欄數據
*/
function customCheckBox(row, col) {
return "<input type='checkbox'>";
}
function customOrgName(row, col) {
var name = row[col.dataField] || "";
return name;
}
function customLook(row, col) {
return "<a href='' style='color:blue;'>查看</a>";
}
/*
展開、關閉所有節點。
isOpen=Y表示展開,isOpen=N表示關閉
*/
function expandAll(isOpen) {
treeGrid.expandAll(isOpen);
}
/*
取得當前選中的行,方法返回TreeGridItem對象
*/
function selectedItem() {
var treeGridItem = treeGrid.getSelectedItem();
if (treeGridItem != null) {
//獲取數據行屬性值
//alert(treeGridItem.id + ", " + treeGridItem.index + ", " + treeGridItem.data.name);
//獲取父數據行
var parent = treeGridItem.getParent();
if (parent != null) {
//jQuery("#currentRow").val(parent.data.name);
}
//獲取子數據行集
var children = treeGridItem.getChildren();
if (children != null && children.length > 0) {
jQuery("#currentRow").val(children[0].data.name);
}
}
}
一、TreeGrid組件相關的類
1、TreeGrid(_config)
_config:json格式的數據,組件所需要的數據都通過該參數提供。
2、TreeGridItem(_root, _rowId, _rowIndex, _rowData)
_root:顯示組件實例的目標容器對象。
_rowId:選中行的id。
_rowIndex:選中行的索引。
_rowData:json格式的行數據。
二、_config參數詳解
id:組件實例的id。
width:組件實例的寬度。
renderTo:用於顯示組件實例的容器對象的id。一般用div作爲容器。
headerAlign:標題行的對齊方式。
headerHeight:標題行的高度。
dataAlign:數據行的對齊方式。
indentation:層級縮進量。
folderColumnIndex:顯示圖標的數據列的索引,從0開始。
folderOpenIcon:節點展開時的圖標。
folderCloseIcon:節點關閉時的圖標。
defaultLeafIcon:葉節點的圖標。
hoverRowBackground:鼠標滑過數據行時,背景色是否改變。
itemClick:單擊數據行後觸發的事件。事件方法包含三個參數,分別是:行的id、行的索引、行數據。
expandLayer:初始展開層數,默認只展開第1層。
columns:值爲數組,數組元素爲json對象。定義數據欄相關信息。
數組元素的屬性:
headerText:欄的標題。
dataField:欄數據對應的字段名。
headerAlign:欄頭對齊方式。
dataAlign:欄數據對齊方式。
width:欄的寬度。
handler:通過指定的方法來自定義欄數據。
folderHidden:在文件夾行隱藏單元格值。
data:組件的數據集。
三、TreeGrid的方法
show:顯示填充數據後的組件對象。
expandAll:展開、關閉所有節點。該方法有一個參數,參數值爲Y時表示展開,參數值爲N時表示關閉。
getSelectedItem:獲取當前選中的數據行,返回TreeGridItem對象。
四、TreeGridItem組件
1、組件屬性
id:數據行的id。
index:數據行的索引。
data:json格式的行數據。
2、組件方法
getParent:獲取父數據行。方法返回TreeGridItem對象。
getChildren:獲取子數據行集。方法返回一個數組,數組元素爲TreeGridItem對象。