在第一篇完成了树的基本展示后,终于有时间接着来完善用户交互部分了。这个版本的代码添加了
1.展开/折叠功能,
2.点击节点时触发相应事件
如下:
计算机
数学
社会学
<script type="text/javascript">
var Tree =
{
Resources:
{
Images:
{
TrunkNode:
{
Expanded: "folder-open.gif",
Collapsed: "folder.gif"
},
LeafNode: "leaf.gif",
Lines:
{
Elbow: "elbow.gif",
ElbowEnd: "elbow-end.gif",
ElbowLine: "elbow-line.gif",
Blank: "blank.gif"
}
}
},
Styles:
{
NodeHeight: "16px"
},
Settings:
{
///<summary>
///点击节点时触发
///</summary>
OnNodeClick: function(node) {
alert(node.innerText || node.textContent);
},
Expanded: false
},
///<summary>
///创建树
///<param name='nodes'>初始要加载的节点(节点的数组,可以使用js字面量也可以用数组:[{"ID":"1", "Name":"Node"}])</param>
///</summary>
BuildTree: function(nodes, parentNode) {
if (nodes && nodes.length > 0) {
//Level 1
for (var i = 0; i < nodes.length; i++) {
var oNode = this._BuildNode(nodes[i], (i == nodes.length - 1) ? true : false, parentNode, this.Settings.Expanded);
this._Fragment.appendChild(oNode);
if (nodes[i].HasChild)//如果有子节点
{
var childNodes = nodes[i].ChildNodes;
this.BuildTree(childNodes, oNode);
}
}
}
this._InitEvent();
},
///<summary>
///创建节点
///<param name="node">节点对象(可以是js字面量,也可以是一般的对象)</param>
///<param name="isLast">判断节点是否为同级的最后一个</param>
///<param name="parentNode">父节点</param>
///</summary>
_BuildNode: function(node, isLast, parentNode, expanded) {
if (node) {
var oNode = document.createElement("div");
oNode.style.height = this.Styles.NodeHeight;
var t = this;
if (node.HasChild) {
oNode.style.cursor = "pointer";
}
if (parentNode) {
oNode.style.display = expanded ? "" : "none";
}
//节点的完整路径,存储从最上层的节点一直到本节点的Index,是为了方便按照level来寻找节点对应level的祖先节点
var nodePath = new Array();
if (parentNode && parentNode.NodePath && parentNode.NodePath.length > 0) {
for (var i = 0; i <= parentNode.NodePath.length - 1; i++) {
nodePath.push(parentNode.NodePath[i]);
}
}
nodePath.push(t._Index);
oNode.NodePath = nodePath;
oNode.innerText = oNode.textContent = "";
//构造相对于父节点的连接线
for (var i = 1; i < node.Level; i++) {
var ancestorNode = t._Nodes[nodePath[i - 1]];
var oImg = document.createElement("img");
oImg.src = ancestorNode.IsLast ? t.Resources.Images.Lines.Blank : t.Resources.Images.Lines.ElbowLine;
oNode.appendChild(oImg);
}
//构造节点本身的连接线
var elbowImg = document.createElement("img");
var elbowImgUrl = t.Resources.Images.Lines.Elbow;
if (isLast)//是同级的最后一个节点,则添加elbow-end.gif
{
elbowImgUrl = t.Resources.Images.Lines.ElbowEnd;
}
elbowImg.src = elbowImgUrl;
oNode.appendChild(elbowImg);
//构造节点类型图片
var imgUrl = t.Resources.Images.TrunkNode.Collapsed;
if (node.IsLeaf) {
imgUrl = t.Resources.Images.LeafNode;
}
var nodeTypeImg = document.createElement("img");
nodeTypeImg.src = imgUrl;
nodeTypeImg.NodeTypeImg = true;
oNode.appendChild(nodeTypeImg);
//节点名字
var oSpan = document.createElement("span");
oSpan.innerText = node.Name;
oSpan.textContent = node.Name;
oSpan.Name = true;
oNode.appendChild(oSpan);
oNode.Index = t._Index;
oNode.ParentNodeIndex = parentNode ? parentNode.Index : null;
oNode.IsLast = isLast;
oNode.IsLeaf = node.IsLeaf;
oNode.Level = node.Level;
oNode.Expanded = expanded;
t._Nodes[t._Index] = oNode;
t._Index++;
return oNode;
}
},
///<summary>
///初始化节点的事件处理程序
///</summary>
_InitEvent: function() {
var t = this;
for (var i = 1; i < t._Nodes.length; i++) {
var node = t._Nodes[i];
for (var j = 0; j < node.childNodes.length; j++) {
if (node.childNodes[j].NodeTypeImg) {
node.childNodes[j].onclick = function() {
var parentNode = this.parentNode;
var childNodes;
if (parentNode.Expanded) {//当前是展开的,需要隐藏后代节点
childNodes = t._FindDescendantNodes(parentNode);
}
else {//当前是收缩的,只需展开子节点即可
childNodes = t._FindChildNodes(parentNode);
}
for (var k = 0; k < childNodes.length; k++) {
childNodes[k].style.display = parentNode.Expanded ? "none" : "";
}
parentNode.Expanded = !parentNode.Expanded;
}
}
else if (node.childNodes[j].Name) {
node.childNodes[j].onclick =
function() {
t.Settings.OnNodeClick.call(this, this);
}
}
}
}
},
_Index: 1,
_Fragment: document.createDocumentFragment(),
_Nodes: new Array(),
///<summary>
///寻找节点子节点
///</summary>
_FindChildNodes: function(node) {
var result = [];
if (this._Nodes.length > 0) {
for (var i = 1; i < this._Nodes.length; i++) {
if (this._Nodes[i].ParentNodeIndex == node.Index) {
result.push(this._Nodes[i]);
}
}
return result;
}
},
///<summary>
///寻找后代节点
///</summary>
_FindDescendantNodes: function(node) {
var result = [];
if (this._Nodes.length > 0) {
for (var i = 1; i < this._Nodes.length; i++) {
if (this._Nodes[i].NodePath.join(",").indexOf(node.NodePath.join(",")) == 0 && this._Nodes[i] != node) {
result.push(this._Nodes[i]);
}
}
return result;
}
}
}
</script>
{
Resources:
{
Images:
{
TrunkNode:
{
Expanded: "folder-open.gif",
Collapsed: "folder.gif"
},
LeafNode: "leaf.gif",
Lines:
{
Elbow: "elbow.gif",
ElbowEnd: "elbow-end.gif",
ElbowLine: "elbow-line.gif",
Blank: "blank.gif"
}
}
},
Styles:
{
NodeHeight: "16px"
},
Settings:
{
///<summary>
///点击节点时触发
///</summary>
OnNodeClick: function(node) {
alert(node.innerText || node.textContent);
},
Expanded: false
},
///<summary>
///创建树
///<param name='nodes'>初始要加载的节点(节点的数组,可以使用js字面量也可以用数组:[{"ID":"1", "Name":"Node"}])</param>
///</summary>
BuildTree: function(nodes, parentNode) {
if (nodes && nodes.length > 0) {
//Level 1
for (var i = 0; i < nodes.length; i++) {
var oNode = this._BuildNode(nodes[i], (i == nodes.length - 1) ? true : false, parentNode, this.Settings.Expanded);
this._Fragment.appendChild(oNode);
if (nodes[i].HasChild)//如果有子节点
{
var childNodes = nodes[i].ChildNodes;
this.BuildTree(childNodes, oNode);
}
}
}
this._InitEvent();
},
///<summary>
///创建节点
///<param name="node">节点对象(可以是js字面量,也可以是一般的对象)</param>
///<param name="isLast">判断节点是否为同级的最后一个</param>
///<param name="parentNode">父节点</param>
///</summary>
_BuildNode: function(node, isLast, parentNode, expanded) {
if (node) {
var oNode = document.createElement("div");
oNode.style.height = this.Styles.NodeHeight;
var t = this;
if (node.HasChild) {
oNode.style.cursor = "pointer";
}
if (parentNode) {
oNode.style.display = expanded ? "" : "none";
}
//节点的完整路径,存储从最上层的节点一直到本节点的Index,是为了方便按照level来寻找节点对应level的祖先节点
var nodePath = new Array();
if (parentNode && parentNode.NodePath && parentNode.NodePath.length > 0) {
for (var i = 0; i <= parentNode.NodePath.length - 1; i++) {
nodePath.push(parentNode.NodePath[i]);
}
}
nodePath.push(t._Index);
oNode.NodePath = nodePath;
oNode.innerText = oNode.textContent = "";
//构造相对于父节点的连接线
for (var i = 1; i < node.Level; i++) {
var ancestorNode = t._Nodes[nodePath[i - 1]];
var oImg = document.createElement("img");
oImg.src = ancestorNode.IsLast ? t.Resources.Images.Lines.Blank : t.Resources.Images.Lines.ElbowLine;
oNode.appendChild(oImg);
}
//构造节点本身的连接线
var elbowImg = document.createElement("img");
var elbowImgUrl = t.Resources.Images.Lines.Elbow;
if (isLast)//是同级的最后一个节点,则添加elbow-end.gif
{
elbowImgUrl = t.Resources.Images.Lines.ElbowEnd;
}
elbowImg.src = elbowImgUrl;
oNode.appendChild(elbowImg);
//构造节点类型图片
var imgUrl = t.Resources.Images.TrunkNode.Collapsed;
if (node.IsLeaf) {
imgUrl = t.Resources.Images.LeafNode;
}
var nodeTypeImg = document.createElement("img");
nodeTypeImg.src = imgUrl;
nodeTypeImg.NodeTypeImg = true;
oNode.appendChild(nodeTypeImg);
//节点名字
var oSpan = document.createElement("span");
oSpan.innerText = node.Name;
oSpan.textContent = node.Name;
oSpan.Name = true;
oNode.appendChild(oSpan);
oNode.Index = t._Index;
oNode.ParentNodeIndex = parentNode ? parentNode.Index : null;
oNode.IsLast = isLast;
oNode.IsLeaf = node.IsLeaf;
oNode.Level = node.Level;
oNode.Expanded = expanded;
t._Nodes[t._Index] = oNode;
t._Index++;
return oNode;
}
},
///<summary>
///初始化节点的事件处理程序
///</summary>
_InitEvent: function() {
var t = this;
for (var i = 1; i < t._Nodes.length; i++) {
var node = t._Nodes[i];
for (var j = 0; j < node.childNodes.length; j++) {
if (node.childNodes[j].NodeTypeImg) {
node.childNodes[j].onclick = function() {
var parentNode = this.parentNode;
var childNodes;
if (parentNode.Expanded) {//当前是展开的,需要隐藏后代节点
childNodes = t._FindDescendantNodes(parentNode);
}
else {//当前是收缩的,只需展开子节点即可
childNodes = t._FindChildNodes(parentNode);
}
for (var k = 0; k < childNodes.length; k++) {
childNodes[k].style.display = parentNode.Expanded ? "none" : "";
}
parentNode.Expanded = !parentNode.Expanded;
}
}
else if (node.childNodes[j].Name) {
node.childNodes[j].onclick =
function() {
t.Settings.OnNodeClick.call(this, this);
}
}
}
}
},
_Index: 1,
_Fragment: document.createDocumentFragment(),
_Nodes: new Array(),
///<summary>
///寻找节点子节点
///</summary>
_FindChildNodes: function(node) {
var result = [];
if (this._Nodes.length > 0) {
for (var i = 1; i < this._Nodes.length; i++) {
if (this._Nodes[i].ParentNodeIndex == node.Index) {
result.push(this._Nodes[i]);
}
}
return result;
}
},
///<summary>
///寻找后代节点
///</summary>
_FindDescendantNodes: function(node) {
var result = [];
if (this._Nodes.length > 0) {
for (var i = 1; i < this._Nodes.length; i++) {
if (this._Nodes[i].NodePath.join(",").indexOf(node.NodePath.join(",")) == 0 && this._Nodes[i] != node) {
result.push(this._Nodes[i]);
}
}
return result;
}
}
}
</script>