论坛首页 Web前端技术论坛

使用javascript以数据和显示相分离的方式实现treeview

浏览 7979 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2005-05-21  
首先定义了clsDataNode,clsTreeNode和clsTree用来对数据建模。
之后,通过一个clsTreeViewVisitor遍历整棵树生成HTML字符串。
clsTreeEventListener和clsDataNodeVisitor用来响应鼠标的点击事件。

附件带有一个完整的示例。这里列举部分的代码。

data.js
function clsDataNode( parentNo, dataNo, name ); {
	this._parentNo = parentNo;
	this._dataNo = dataNo;
	this._name = name;

	this.getParentNo=function(); {
		return this._parentNo;
	}
	
	this.getNo=function(); {
		return this._dataNo;
	}
	
	this.getName=function(); {
		return this._name;
	}
}

function clsDataNodeUtils(); {}
{
	clsDataNodeUtils.dataNodeCmpFunc=function( node, dataNo ); {
		var ret = 0;
		if( node.getNo(); > dataNo ); ret = 1;
		if( node.getNo(); < dataNo ); ret = -1;
		
		return ret;
	}
}



tree.js
function clsTreeNode( dataNode ); {

	this._dataNode = dataNode;
	this._parent = null;
	this._children=new Array();;
	
	this.getParent=function(); {
		return this._parent;
	}
	
	this.addChild=function( treeNode );{
		this._children[ this._children.length ] = treeNode;
		treeNode._parent = this;
	}
	
	this.getChildren=function(); {
		return this._children;
	}
	
	this.getCountOfChildren=function(); {
		var total = this._children.length;
		for( var i = 0; i < this._children.length; i++ ); {
			total = total + this._children[i].getCountOfChildren();;
		}
		
		return total;
	}
	
	this.getPath=function(); {
		var path = "";
		var tmp = this;
		while( null != tmp ); {
			if( path.length == 0 ); {
				path = tmp.getDataNode();.getName();;
			} else {
				path = tmp.getDataNode();.getName(); + "/" + path;
			}
			tmp = tmp.getParent();;
		}
		
		return path;
	}
	
	this.getLevel=function();{
		var level = 0;
		var tmp = this._parent;
		while( null != tmp ); {
			level = level + 1;
			tmp = tmp._parent;
		}
		return level;
	}
	
	this.getDataNode=function(); {
		return this._dataNode;
	}
	
	this.setDataNode=function( dataNode ); {
		this._dataNode = dataNode;
	}
}

function clsTree( dataNodeCmpFunc ); {
	this._dataNodeCmpFunc = dataNodeCmpFunc;
	this._root = null;
	
	this.getRoot=function(); {
		return this._root;
	}
	
	this.depthTravelInternal=function( startNode, visitor ); {
		var myResult = null;
		
		var children = startNode.getChildren();;
		for( var i = 0; i < children.length; i++ ); {
			if( null == myResult ); {
				myResult = this.depthTravelInternal( children[i], visitor );;
			} else {
				var resultType = typeof myResult;
				if( resultType == "number" || resultType == "string" ); {
					myResult = myResult + this.depthTravelInternal( children[i], visitor );;
				}
				if( resultType == "object" && myResult.constructor == Array ); {
					myResult = myResult.concat( this.depthTravelInternal( children[i], visitor ); );;
				}
			}
		}
		
		return visitor.visit( startNode, myResult );;
	}
	
	this.depthTravel=function( visitor );{	
		return this.depthTravelInternal( this._root, visitor );;
	}

	this.addNode=function( parentInfo, dataNode ); {
		var ret = false;
		if( null == this._root || null == parentInfo ); {
			this._root = new clsTreeNode( dataNode );;
			ret = true;
		} else {
			var parent = this.getNode( parentInfo );;
			if( null != parent ); {
				parent.addChild( new clsTreeNode( dataNode ); );;
				ret = true;
			} else {
				//alert( "Cannot find tree node : " + parentInfo );;
				ret = false;
			}
		}
		return ret;
	}
	
	this.getNode=function( nodeInfo ); {
		return this.getNodeInternal( this._root, nodeInfo );;
	}
	
	this.getNodeInternal=function( startNode, nodeInfo ); {
		if( null == startNode ); return null;
		
		var ret = null;
		if( 0 == this._dataNodeCmpFunc( startNode.getDataNode();, nodeInfo ); ); {
			ret = startNode;
		} else {		
			var children = startNode.getChildren();;
			for( var i = 0; i < children.length; i++ ); {
				ret = this.getNodeInternal( children[i], nodeInfo );;
				if( null != ret ); break;
			}
		}
		
		return ret;
	}	
}

clsTree.addNodeListToTree=function( oTree, nodeList ); {
	var stop = false;
	while( !stop ); {
		stop = true;
		for( var i = 0; i < nodeList.length; i++ ); {
			var node = nodeList[i];
			if( null != node ); {
				if( oTree.addNode( node.getParentNo();, node ); ); {
					nodeList[i] = null;
					stop = false;
				} else {
					//alert( "Add " + node.getNo(); + " to " + node.getParentNo(); + " fail!" );;
				}
			}
		}
	}

	return oTree;
}

   发表时间:2005-05-21  
问题:
1、不支持 IE5,在 Firefox 下可以正常显示。
2、完全使用 table 来制作。以现在的眼光来看已经落后了。
3、没有实现 structure、presentation 和 behaviour 的分离。

建议学习一下我贴的使用 UL 做的那个 tree 的例子。
0 请登录后投票
   发表时间:2005-05-22  
描述一下我对dlee的话的理解。

structure、presentation 和 behaviour 都是属于显示这个范畴的。

在这个treeview解决方案中
1.structure方面,是由javascript来生成。这个做法的好处是服务器端可以直接把原始的基于数据库的平面数据(二维表)输出到页面上,由javascript来把平面数据组织成为一棵树。如果不想用javascript来生成structure,那么就需要在服务器端把这些平面数据组织成一棵树,根据这棵树直接生成所需要的structure。
2.presentation 方面,由于使用了table,部分的页面布局功能已经从structure方面就决定了。剩下的presentation 主要有两点:1)每个节点前面显示的图片;2)整个树显示的文字的风格方面的控制。在实际使用中,可以在clsTreeViewVisitor中的构造函数中添加参数,用来指定这些信息。
3.behaviour 方面,现在从代码角度来看是分开的,由clsTreeEventListener来处理鼠标的点击事件。但是clsTreeEventListener还是依赖于由table组成的structure的。

在这个treeview解决方案中,structure、presentation 和 behaviour 3个方面中:
1.structure和presentation 没有分离好。需要更好地抽取treeview的显示风格中有可能变化的部分,把这些东西作为clsTreeViewVisitor的构造参数。
2.structure和behaviour 没有分离好?这个应该如何分离?我看了UL的例子,里面体现structure和behaviour 分离的代码是不是指这一段?
function associateTree(a,ul); {
    if (a.parentNode.className.indexOf('open'); == -1); {
        a.parentNode.className = 'closed';
    }
    a.onclick = function (); {
        this.parentNode.className = (this.parentNode.className=='open'); ? "closed" : "open";
        return false;
    }
}

3.在这个treeview解决方案中,presentation 和 behaviour 是分离的。
0 请登录后投票
   发表时间:2005-05-22  
基本上没有理解我说的话。
structure 和 presentation 分离,意味着 table 不应该再被用来做布局,而只应该被用来做它最初被设计用来做的事情——容纳表格类的数据。而你的方法是完全采用 table 来做布局。
presentation 和 behaviour 分离,意味着 js 中不应该再包含直接设置 style 的代码,这样如果用户对 style 不满意,你仍然需要修改 js 代码。
structure 和 behaviour 分离,意味着在 html/xhtml 中,完全不应该存在任何 js 代码和 onclick 一类的事件函数设置。

还是建议你再仔细看一下我改好的那个 tree 的例子。以我的观点,我认为这代表了一些先进的东西。当然我们可以继续讨论。
在那个例子中,完全相同的 ul 结构只需要设置不同的 class,就可以变成完全不同的样式,你是不是有点明白我在说什么了?
0 请登录后投票
   发表时间:2005-05-22  
dlee,你的那个例子的网址在哪里?让我好一通找......
0 请登录后投票
   发表时间:2005-05-22  
http://forum.iteye.com/viewtopic.php?t=12995
我发的例子一般都很注意注明原始出处的,里面有的。
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics