以前在vs2003,2005中都用过treeview控件
最近的project要求无刷新使用treeview控件,因为事件的响应都是javascript完成的,开始没觉得是个big issue,但是后来发现花费了我很多时间来完成。
我们知道在。net3.5中treeview会自动生成一个script resource文件(如果使用了scriptmanager的话),或者是webresource文件,具体内容如下:
function
TreeView_HoverNode( data, node) {
if (!data) {
return;
}
node.hoverClass = data.hoverClass;
WebForm_AppendToClassName(node, data.hoverClass);
if (__nonMSDOMBrowser) {
node = node.childNodes[node.childNodes.length - 1];
}
else {
node = node.children[node.children.length - 1];
}
node.hoverHyperLinkClass = data.hoverHyperLinkClass;
WebForm_AppendToClassName(node, data.hoverHyperLinkClass);
}
function
TreeView_GetNodeText( node) {
var trNode = WebForm_GetParentByTagName(node, "TR");
var outerNodes;
if (trNode.childNodes[trNode.childNodes.length - 1].getElementsByTagName) {
outerNodes = trNode.childNodes[trNode.childNodes.length - 1].getElementsByTagName("A");
if (!outerNodes || outerNodes.length == 0) {
outerNodes = trNode.childNodes[trNode.childNodes.length - 1].getElementsByTagName("SPAN");
}
}
var textNode = (outerNodes && outerNodes.length > 0) ?
outerNodes[0].childNodes[0] :
trNode.childNodes[trNode.childNodes.length - 1].childNodes[0];
return (textNode && textNode.nodeValue) ? textNode.nodeValue : "";
}
function
TreeView_PopulateNode( data, index, node, selectNode, selectImageNode, lineType, text, path, databound, datapath, parentIsLast) {
if (!data) {
return;
}
var context = new Object();
context.data = data;
context.node = node;
context.selectNode = selectNode;
context.selectImageNode = selectImageNode;
context.lineType = lineType;
context.index = index;
context.isChecked = "f";
var tr = WebForm_GetParentByTagName(node, "TR");
if (tr) {
var checkbox = tr.getElementsByTagName("INPUT");
if (checkbox && (checkbox.length > 0)) {
for (var i = 0; i < checkbox.length; i++) {
if (checkbox[i].type.toLowerCase() == "checkbox") {
if (checkbox[i].checked) {
context.isChecked = "t";
}
break;
}
}
}
}
var param = index + "|" + data.lastIndex + "|" + databound + context.isChecked + parentIsLast + "|" +
text.length + "|" + text + datapath.length + "|" + datapath + path;
TreeView_PopulateNodeDoCallBack(context, param);
}
function
TreeView_ProcessNodeData( result, context) {
var treeNode = context.node;
if (result.length > 0) {
var ci = result.indexOf("|", 0);
context.data.lastIndex = result.substring(0, ci);
ci = result.indexOf("|", ci + 1);
var newExpandState = result.substring(context.data.lastIndex.length + 1, ci);
context.data.expandState.value += newExpandState;
var chunk = result.substr(ci + 1);
var newChildren, table;
if (__nonMSDOMBrowser) {
var newDiv = document.createElement("div");
newDiv.innerHTML = chunk;
table = WebForm_GetParentByTagName(treeNode, "TABLE");
newChildren = null;
if ((typeof(table.nextSibling) == "undefined") || (table.nextSibling == null)) {
table.parentNode.insertBefore(newDiv.firstChild, table.nextSibling);
newChildren = table.previousSibling;
}
else {
table = table.nextSibling;
table.parentNode.insertBefore(newDiv.firstChild, table);
newChildren = table.previousSibling;
}
newChildren = document.getElementById(treeNode.id + "Nodes");
}
else {
table = WebForm_GetParentByTagName(treeNode, "TABLE");
table.insertAdjacentHTML("afterEnd", chunk);
newChildren = document.all[treeNode.id + "Nodes"];
}
if ((typeof(newChildren) != "undefined") && (newChildren != null)) {
TreeView_ToggleNode(context.data, context.index, treeNode, context.lineType, newChildren);
treeNode.href = document.getElementById ?
"javascript:TreeView_ToggleNode(" + context.data.name + "," + context.index + ",document.getElementById('" + treeNode.id + "'),'" + context.lineType + "',document.getElementById('" + newChildren.id + "'))" :
"javascript:TreeView_ToggleNode(" + context.data.name + "," + context.index + "," + treeNode.id + ",'" + context.lineType + "'," + newChildren.id + ")";
if ((typeof(context.selectNode) != "undefined") && (context.selectNode != null) && context.selectNode.href &&
(context.selectNode.href.indexOf("javascript:TreeView_PopulateNode", 0) == 0)) {
context.selectNode.href = treeNode.href;
}
if ((typeof(context.selectImageNode) != "undefined") && (context.selectImageNode != null) && context.selectNode.href &&
(context.selectImageNode.href.indexOf("javascript:TreeView_PopulateNode", 0) == 0)) {
context.selectImageNode.href = treeNode.href;
}
}
context.data.populateLog.value += context.index + ",";
}
else {
var img = treeNode.childNodes ? treeNode.childNodes[0] : treeNode.children[0];
if ((typeof(img) != "undefined") && (img != null)) {
var lineType = context.lineType;
if (lineType == "l") {
img.src = context.data.images[13];
}
else if (lineType == "t") {
img.src = context.data.images[10];
}
else if (lineType == "-") {
img.src = context.data.images[16];
}
else {
img.src = context.data.images[3];
}
var pe;
if (__nonMSDOMBrowser) {
pe = treeNode.parentNode;
pe.insertBefore(img, treeNode);
pe.removeChild(treeNode);
}
else {
pe = treeNode.parentElement;
treeNode.style.visibility="hidden";
treeNode.style.display="none";
pe.insertAdjacentElement("afterBegin", img);
}
}
}
}
function
TreeView_SelectNode( data, node, nodeId) {
if (!data) {
return;
}
if ((typeof(data.selectedClass) != "undefined") && (data.selectedClass != null)) {
var id = data.selectedNodeID.value;
if (id.length > 0) {
var selectedNode = document.getElementById(id);
if ((typeof(selectedNode) != "undefined") && (selectedNode != null)) {
WebForm_RemoveClassName(selectedNode, data.selectedHyperLinkClass);
selectedNode = WebForm_GetParentByTagName(selectedNode, "TD");
WebForm_RemoveClassName(selectedNode, data.selectedClass);
}
}
WebForm_AppendToClassName(node, data.selectedHyperLinkClass);
node = WebForm_GetParentByTagName(node, "TD");
WebForm_AppendToClassName(node, data.selectedClass)
}
data.selectedNodeID.value = nodeId;
}
function
TreeView_ToggleNode( data, index, node, lineType, children) {
if (!data) {
return;
}
var img = node.childNodes[0];
var newExpandState;
try {
if (children.style.display == "none") {
children.style.display = "block";
newExpandState = "e";
if ((typeof(img) != "undefined") && (img != null)) {
if (lineType == "l") {
img.src = data.images[15];
}
else if (lineType == "t") {
img.src = data.images[12];
}
else if (lineType == "-") {
img.src = data.images[18];
}
else {
img.src = data.images[5];
}
img.alt = data.collapseToolTip.replace(//{0/}/, TreeView_GetNodeText(node));
}
}
else {
children.style.display = "none";
newExpandState = "c";
if ((typeof(img) != "undefined") && (img != null)) {
if (lineType == "l") {
img.src = data.images[14];
}
else if (lineType == "t") {
img.src = data.images[11];
}
else if (lineType == "-") {
img.src = data.images[17];
}
else {
img.src = data.images[4];
}
img.alt = data.expandToolTip.replace(//{0/}/, TreeView_GetNodeText(node));
}
}
}
catch(e) {}
data.expandState.value = data.expandState.value.substring(0, index) + newExpandState + data.expandState.value.slice(index + 1);
}
function
TreeView_UnhoverNode( node) {
if (!node.hoverClass) {
return;
}
WebForm_RemoveClassName(node, node.hoverClass);
if (__nonMSDOMBrowser) {
node = node.childNodes[node.childNodes.length - 1];
}
else {
node = node.children[node.children.length - 1];
}
WebForm_RemoveClassName(node, node.hoverHyperLinkClass);
}
if
( typeof( Sys)!== 'undefined') Sys. Application. notifyScriptLoaded();
这就是所有的treeview客户端方法,并且根据aspx页面生成的html页面,我们会看到,每个节点是个table,子节点在对应的div中,收缩和展开只要是通过div的显示和隐藏来实现的。所以我们在每添加一个节点的时候,就先添加一个table,然后添加一个div,作为他的子节点容器。
addItemToTreeView(){
..............
addTable(....);
var divID = "...";
addDiv(divID, containerId); //id,containerId
addSubTable(divID,...);
addSubTable(divID,...);
}
添加div
function
addDiv( id, containerID) {
var container = document.getElementById(containerID);
var div = document.createElement("div");
div.setAttribute("id", id);
div.setAttribute("style", "display=block");
container.appendChild(div);
}
添加table
function
addTable( containerId, index, name, color) {var container = document.getElementById(containerId);
var table = document.createElement("table");
table.setAttribute("cellSpacing", "0");
table.setAttribute("cellPadding", "0");
table.setAttribute("border", "0");
var _tr = table.insertRow(-1);
var _td1 = _tr.insertCell(0);
_td1.innerHTML = "<div style=/"width: 20px; height: 1px/"></div>";
var _td2 = _tr.insertCell(1);
_td2.innerHTML = "<div style=/"width: 20px; height: 1px/"></div><img src=" + ModelTreeView_Data.images[6] + " alt=/"/" /></div>";
var _td3 = _tr.insertCell(2);
_td3.setAttribute("id", id);
_td3.innerHTML = "<a href=/"javascript:TreeView_ToggleNode1(TreeView_Data," + index + ",document.getElementById('nodeId'),'t',document.getElementById('divId'))/"><img src=" + TreeView_Data.images[5] + " alt=/"Collapse " + name + "/" style=/"border-width:0;/" /></a>";
var _td4 = _tr.insertCell(3);
_td4.innerHTML = "<a class=/"TreeView_0/" href=/"javascript:void(0);/" id=/"TreeViewt" + index + "/" style=/"color:" + color + "/">" + name + "</a>";
_td4.setAttribute("style", "color:"+color);
container.appendChild(table);
}
添加table时候有几个需要注意的地方,就是treeview会自动生成一个TreeView_Data(TreeView 是id)数据,其中包括了图片等信息,还有我们刚才看到scriptresource文件中有TreeView_ToggleNode方法,直接调用便可。还有就是treeview中的节点都是按序编号的。
至于点击节点的时候要求不刷新的话,可以添加节点属性href="javascript:void(0);", 还有展开收缩刷新问题,可以通过设置node.SelectAction = TreeNodeSelectAction.Expand;
由于系统中没有使用javascript框架,所以所有代码的都是纯javascript,如果能够对需要的朋友带来帮助。如果需要运行,需要修改其中对应的部分。