追海逐风

导航

javascript树形控件第二版

使用了prototype的自定义事件;进一步抽象了树节点。数据还是用上个版本的随机数据。

都写在一个HTML中了。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test Tree</title>
<script type="text/javascript" src="js/prototype.js"></script>
<script type="text/javascript">
	var Tree = Class.create({
		initialize: function(config) {
			this.parent = config.parent;
			this.data = config.data;
			this.getLabel = config.getLabel;
			this.getChildren = config.getChildren;
			
			this.parent.observe('tree:nodeclick', function(){});
			this.parent.observe('tree:selectchanged', function(){});
		},
		observe: function(eventName, handler) {
			this.parent.observe(eventName, handler);
		},
		load: function() {
			var me = this;
			
			this.root = this._postTraverseData(this.data, 0, makeNode);
			this._buildTree(this.root);
			
			this._postTraverseNode(this.root, 0, createBuildinBehaviour);
			
			function makeNode(o, level, children) {
				var node = me._buildTreeNode(me.getLabel(o), null, null, children, level);
				return node;
			}
			
			function createBuildinBehaviour(node) {
				node.treeButton.observe('click', function (e) {
					var button = e.findElement();
					var tree = e.findElement('li');
					if (tree.childTreesContainer) {
						tree.childTreesContainer.toggle();
						button.toggleButton();
					}
				});
				
				node.treeLabel.observe('click', function(e) {
					var node = e.findElement('li');
					if (me.selectedNode != node) {
						var old = me.selectedNode;
						me.selectedNode = node;
						me.parent.fire('tree:selectchanged', {old: old, current: node});
					}
					
					me.parent.fire('tree:nodeclick', {node: node});
				});
			}
		},
		_postTraverseData: function(o, level, callback) {
			var children = this.getChildren(o);
			var results = [];
			if (children) {
				for (var i = 0, n = children.length; i < n; ++i) {
					results.push(this._postTraverseData(children[i], level + 1, callback));
				}
			}
			return callback(o, level, results);
		},
		_postTraverseNode: function(node, level, callback) {
			var results = null;
			if (node.childTreesContainer) {
				results = [];
				var childTrees = node.childTreesContainer.childElements();
				for (var i = 0, n = childTrees.length; i < n; ++i) {
					results.push(this._postTraverseNode(childTrees[i], level + 1, callback));
				}
			}
			return callback(node, level, results);
		},
		_buildTreeNode: function(label, button, toggleButton, childTrees, level) {
			var eNode = new Element('li');
			
			var eButton;
			if (Object.isElement(button)) {
				eButton = button;
			} else {
				eButton = new Element('a').update('[-]');
				eButton.href = 'javascript:void(0)';
			}
			if (!eButton.toggleButton) {
				eButton.toggleButton = toggleButton ? toggleButton : function() {
					this.update(this.innerHTML == '[-]' ? '[+]' : '[-]');
				}
			}
			eNode.appendChild(eButton);
			eNode.treeButton = eButton;
			
			var eLabel = Object.isElement(label) ? label : new Element('span').update(label.toString());
			eNode.appendChild(eLabel);
			eNode.treeLabel = eLabel;
			
			if (Object.isArray(childTrees) && childTrees.length > 0) {
				var eChildTreesContainer = new Element('ul');
				for (var i = 0, n = childTrees.length; i < n; ++i) {
					eChildTreesContainer.appendChild(childTrees[i]);
				}
				eNode.appendChild(eChildTreesContainer);
				eNode.childTreesContainer = eChildTreesContainer;
			}
			return eNode;
		},
		_buildTree: function(root) {
			var ul = new Element('ul');
			ul.appendChild(root);
			this.parent.appendChild(ul);
		}
	});
	function randomData(level) {
		var CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789';
		var CHARS_LENGTH = CHARS.length;
	 
		return createData(level);
	 
		// 真正干活的函数。
		function createData(level) {
			var o = {};
			o.label = randomString(10);
	 
			if (level > 0) {
				var seed = randomInt(0, 10);
				if (seed > 2) {
					o.children = new Array(randomInt(2, 4));
					for (var i = 0, n = o.children.length; i < n; ++i) {
						o.children[i] = createData(level - 1);
					}
				}
			}
			return o;
		}
		 
		// 随机整数,[bottom, top)
		function randomInt(bottom, top) {
			return Math.floor(Math.random() * (top - bottom)) + bottom;
		}
	 
		// 使用CHARS生成随机字符串。length:字符串长度,返回的字符串一定是这个长度。用数组join的方法实现,高效简洁。
		function randomString(length) {
			var a = new Array(length);
			for (var i = 0; i < length; ++i) {
				a[i] = CHARS.charAt(randomInt(0, CHARS_LENGTH));
			}
			return a.join('');
		}
	}

	Event.observe(window, 'load', function() {
		var t = new Tree({
			parent: $('divTree'),
			data: randomData(3),
			getLabel: function(o) {
				return o.label;
			},
			getChildren: function(o) {
				return o.children;
			}
		});
		t.observe('tree:nodeclick', function(e) {
			$('txtLabel').setValue(e.memo.node.treeLabel.innerHTML);
		});
		t.observe('tree:selectchanged', function(e) {
			var old = e.memo.old;
			var current = e.memo.current;
			$('divMessage').update((old ? old.treeLabel.innerHTML : 'null') + " -> " + current.treeLabel.innerHTML);
		});
		t.load();
		
		$('btnUpdate').observe('click', function() {
			if (t.selectedNode) {
				t.selectedNode.treeLabel.update($F('txtLabel'));
			}
		});
	});
</script>
</head>
<body>
<div id="divTree"></div>
<input id="txtLabel" type="text" />
<input id="btnUpdate" type="button" value="Update" />
<div id="divMessage"></div>
</body>
</html>

posted on 2010-08-09 13:22  追海逐风  阅读(465)  评论(0编辑  收藏  举报