﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-兴趣与爱好-文章分类-Tree Crontol</title><link>http://www.blogjava.net/kennyr/category/33131.html</link><description>学习交流</description><language>zh-cn</language><lastBuildDate>Tue, 22 Jul 2008 02:15:33 GMT</lastBuildDate><pubDate>Tue, 22 Jul 2008 02:15:33 GMT</pubDate><ttl>60</ttl><item><title>MzTreeView节点树</title><link>http://www.blogjava.net/kennyr/articles/215979.html</link><dc:creator>-南风</dc:creator><author>-南风</author><pubDate>Sat, 19 Jul 2008 03:07:00 GMT</pubDate><guid>http://www.blogjava.net/kennyr/articles/215979.html</guid><wfw:comment>http://www.blogjava.net/kennyr/comments/215979.html</wfw:comment><comments>http://www.blogjava.net/kennyr/articles/215979.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kennyr/comments/commentRss/215979.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kennyr/services/trackbacks/215979.html</trackback:ping><description><![CDATA[<div class="storytext">MzTreeView 一次加载数据的树
<p><br />
<p>好东西当然要与大家分享。。。<a href="http://jasonhero.itpub.net/"><font color="#007799">@与羊共舞的狼</font></a> </p>
<p class="Attention">MzTreeView 1.0 from---&gt;&gt;&gt; <a href="http://www.meizz.com/">http://www.meizz.com/</a> </p>
<p>开发文档: <a href="http://www.meizz.com/Web/Article.asp?id=436" target="_blank">http://www.meizz.com/Web/Article.asp?id=436</a><br />
控件下载: <a href="http://www.meizz.com/Web/Download/MzTreeView10.rar" target="_blank">http://www.meizz.com/Web/Download/MzTreeView10.rar</a><br />
应用示例: <a href="http://www.meizz.com/Web/Demo/MzTreeView10.htm" target="_blank">http://www.meizz.com/Web/Demo/MzTreeView10.htm</a> </p>
<dt>说明
<dd>MzTreeView 1.0 是数据一次性加载，客户端节点异步展示的WEB脚本树。MzTreeView 1.0 的理论节点数设计上限为十万节点，在节点数三万的情况下页面打开时间小于 3 秒。无限层次无限节点的数的层级组成方式：id parentId。即每个节点除本身的节点id之外还有它的父层节点id，通过这种方式就可以组合成无限层级的树了。<br />
<br />
在 MzTreeView 里都有一个虚的根节点，其ID为0，用户可见的根节点其父节点ID皆为0<br />
<br />
MzTreeView 1.0在数据库库表里的字段名称：
<div class="Article">
<table cellspacing="1" border="0">
    <tbody>
        <tr>
            <th>字段名</th>
            <th>字段的具体说明</th>
        </tr>
        <tr>
            <td>id</td>
            <td>节点ID（不可为0，可以是数字或字符）</td>
        </tr>
        <tr>
            <td>parentId</td>
            <td>本节点的父节点ID（若本节点已为根节点，此处填0）</td>
        </tr>
        <tr>
            <td>text</td>
            <td>节点的显示文本（一般不允许为空，不过有一种情况例外，即根节点，若根节点文本为空，这个根节点将不会在页面里显示）</td>
        </tr>
        <tr>
            <td>hint</td>
            <td>节点的说明注解</td>
        </tr>
        <tr>
            <td>icon</td>
            <td>节点的图标，MzTreeView 1.0允许每个节点拥有不同的图标（对应的名字在类里的icons和iconsExpand定义）</td>
        </tr>
        <tr>
            <td>data</td>
            <td>节点挂的数据，格式是 param=value&amp;param=value&amp;... url里?后的那串字符串格式，</td>
        </tr>
        <tr>
            <td>url</td>
            <td>每个节点允许拥有不同的链接，它为空或者为#时，树里这个节点的链接，点击将无反应</td>
        </tr>
        <tr>
            <td>target</td>
            <td>每个节点的链接允许在不同的target里打开，为空时取类里的默认值</td>
        </tr>
        <tr>
            <td>method</td>
            <td>点击该链接时所想触发的脚本语句</td>
        </tr>
    </tbody>
</table>
特注：每个字段值中不可有冒号： 不可以换行 引号酌情考虑应不与节点字符串的引号相冲突</div>
<dt>设计模式
<dd>为了达到能够在浏览器中快速打开多节点树的页面，我做了很多的优化与创新，下面我将详细解说几项最重要的部分：<br />
<br />
<ul>
    <li><strong>数据一次性加载</strong> 首先我要说的就是数据的一次性加载。在目前的 B/S 架构开发中对于多节点多层次的树，特别是树节点量超过两千的情况下，几乎都是采取数据异步加载来达到目的，即用户需要展开某个节点时，再从服务器端加载下级子节点的数据，数据异步加载最为经典的例子就是 MSDN 网站左边的目录树了。异步加载的优点在于可以扩充到无限级无限节点树，树的数据来源可以多样化（数据库或XML文件）等，但是它的缺点也是非常多的：设计模式比数据一次性加载要复杂得多，要考虑到 Browser/Server 之间的应答，要判断子节点是否含有孙节点，后台数据源的层级关系模型等。对网络传输的信赖性太大，每个节点的展开都需要连一次 Server，只要在取某节点数据时网络出现问题，就会导致该节点及其以下的子节点加载失败。而采取数据一次加载的模式只要一次加载成功，服务器就可以不用管它了，服务器压力减轻，脚本设计则完全独立，对整棵树节点的检索可以在客户端完成，节点展开响应速度快等等优势，因此在节点数不多的情况下数据一次性加载更有优势，那么这个节点数不多不多到底多少节点量为平衡点呢？就 ASP.net 里带的那个 TreeView 来说，在一两千节点以下一次性加载比较具有优势，而　MzTreeView 1.0 在节点量三万至五万以非常具有优势。
    <li><strong>节点信息的压缩传输</strong> 在浏览器里显示的树结构其实都是一个个 HTML 元素组合起来的，在 WEB 页面里的树都是根据树节点的信息组合成一串的 HTML 元素列来显示，这一步从节点信息到 HTML 的转化可以在两个地方生成：一个是在服务器端，一个是在客户端。在服务器端生成的优点在于不须考虑客户端的浏览器的兼容性，节点信息的可控性非常强，但是它的缺点也是非常大的：加重服务器的负担，增加网络传输量。在服务器端直接生成树节点的 HTML 给服务器带来的压力是显而易见的，也是非常巨大的，估计只要有几十个并发连接就能让服务器暂时停止响应了。这种直接在服务器生成树的做法在实际运用环境中也有人使用，不过本人非常不赞成这种做法。当然也有人直接将树生成为一个静态文件放在服务器端，这种做法对于树节点相对固定不变的情况还是非常有利的，只需要生成一次，以后就不需要再生成了，服务器的压力也非常小，但它的弊病在于可变化性太小，比如说不同的权限能看到的树节点的不同这种情况，用这种生成静态树放在服务器端的做就没有办法解决，且不管是服务器端动态计算还是直接生成静态树文件放在服务器端都有一个避免不了的问题就是网络传输量巨大。可以计算一下，一个树点所需要的HTML字符量大约300到600字节之间。即含有一千节点的树的网页大小就有300K到600K，给网络造成的压力是非常巨大的，所以MzTreeView 1.0采用了节点信息的压缩传输，大至一千节点的总传输量在30K左右，这可以差了一个数量级呀。本树将每个节点所必要的信息组合成一个字符串序列，传递到客户端，然后在客户端再用客户端脚本对这些信息进行分析，再生成一个个的节点HTML，这也符合了WEB的分散计算的原理，当然服务器端可以有选择性输出部分节点，这样又做到节点的灵活多变性。
    <li><strong>传输的节点信息的可扩展性</strong> 服务器端将节点的必要信息组合成一个字符串序列传递到客户端，然后客户端再用脚本对这个字符串序列进行分析，生成树的节点，那么这个字符串序列对整个树的生成的效率就有重要的影响了。我也参照过很多组串传输的例子，在一般的做法当中大多采用函数的参数方式传递。比如说定义一个函数 funName(p1, p2, p3, ...)，然后服务器组串的时候就按位置给定数据。这种组串的弊病是非常大的，首先就是位置绝对错不得，只要有一个位置数据出错，这个节点的信息就乱了，对于那些在函数里已经定义的但节点里没有的信息也得用空字符串补上，诸如：(p1, "", p3, p4, "", "", "")，且万一这种组串的对应分析函数发生了变化，那么这种串就算是废了，得重新定义服务器端的字符串位置序列了，可以说这种组串的方式可扩展性极差。<br />
    节点信息组串传输的另一种常用模式就是XML。XML以它的无限可扩展性已惭有代替HTML称霸WEB的味道了。XML最大的优点就在于它的无限可扩展性，可以用任意的TagName名，可以有任意的Attribute名，节点与子节点已经有层级的关系，用XML来做WEB树的数据源其实是最理想的，MSDN的资源目录树就是采用XML作为传递的字符串，它唯一的不足之处就是不是所有浏览器都能很好地支持它，特别是在一些低版本的浏览器中，所以我只好忍痛割爱没有启用XML作为中间的传媒。那么是不是有可能结合XML的扩展性对第一种组串的方式进行改进呢？当我愁眉不展的时候，HTML里的STYLE样式表写法跳入我眼，样式的写法是"param1: value1; param2: value3; ..."，哈哈，这不是现成地给我指明了路吗？这种写法拥有XML的可扩展性，位置顺序的随意性，又是传统的长字符串，正合我意也！服务器给定这种数据源字符串，我不光可以在TreeView里用它，还可以直接做Outlook Bar，下拉式层级菜单，右键层级菜单的数据源，豁然开朗也！我写了一个函数专门解析这种文本：getAttribute()。
    <li><strong>客户端节点数据的存储方式及快速检索</strong> 现在数据源准备好了，数据传输也已做到最大优化了，下面就是客户端的脚本解析了，而这一步也正是树生成的效率瓶颈所在。由于我没有采用XML做为数据源，所以我这里就不讨论XML+XSL和XMLDOM的模式，而只考虑HTML+DOM模式了。在HTML+DOM模式下客户端存储的方式有很多种，我就曾经看到过一种直接将字符串输出在多行文本框<a href="http://jasonhero.itpub.net/302/406.htm">&lt;textarea&gt;</a>里的，但归究起来最常用的方式就是用一个数组来存放节点信息，不过就算是用数组也是种类多多，比如说数组里套数组，节点通过记录父节点在数组里的索引号表示层级的等等，说到数组存放树节点模式，我推荐阿信写的那棵树。在服务器端组织好脚本及节点字符串，客户端浏览器加载这个页面的时候顺序执行其里面的脚本，将一个个节点做最初步的解析，然后再一个个地ADD到数组中去。这种流程看起来似乎没有什么问题，在很多的传统C/S结构编程中也就这种模式，但是随着节点数的增多，这种流程在B/S里的缺点就出现了：脚本的执行效率不如强语言高！我做过测试，在5000节点的数据量时这一步操作将耗时１秒钟，也许你认为这１秒钟不算长，哪里有5000这么多节点的树？但对于一个程序员来说，严谨是第一位的，若存在优化的可能性，情况出现的可能性，我们就得将它考虑到。那么有没有可能再进一步优化呢？当然有，否则我就用不着这么大费口舌在这里讲了。既然在脚本里执行 for 循环插入数组效率不高那我不用循环，且考虑到在数组里这么多节点中搜索我想要的某几个节点，还得用循环，所以我干脆就不再用数组来存放树节点了，那用什么呢？说到这里我得插几句题外话，客户端脚本也可以写一些类，虽说写出来的类没有强语言那么好，继承性不好等，但脚本终究还是可以写出一些简单的类的。类可以定义属性，也可以定义方法，并且访问属性的时候可以通过属性名下标直接访问到属性值，关于脚本里如何写类，大家可以参考我在JavaScript和VBScript里对这方面的详细说明。呵呵，说了这么多的题外话，不过相信大家也猜到了，新的节点存储方式就是类的属性自定义扩展方式。这种存储方式随着页面的打开，页面里的脚本被执行，类的属性值不需要做任何添加的动作就直接写到内存当中，比数组模式少去了ADD操作，这一步从字符串到内存的时间就是页面打开的时间，我测试了一下，5000节点的树用这种方式打开，只需0.1秒呀，与数组模式速度整整差了一个数量级呀！且这种模式还有一种好处，在几千个节点里要找到目标节点，只需要知道节点对应的属性名，一步就可以直接找到。<br />
    客户端树节点存储模式说清楚了，那节点的快速检索也就清楚了。已知节点名即在类里的属性名的话，一步就找到了该节点，不过为了配合下一节的异步展示，我的检索就没有这么简单了。试想在几千或者几万个节点里要快速地找出符合条件的几十个节点，这一步的耗时可想而知了，首先就得排除for循环法，for循环的效率在数组模式里大家就看到了，这一步操作特别在总节点数多的情况下就能让使用者等疯掉，显然得另想办法。于是我想到了正则表达式里的字符串模式匹配<a href="http://jasonhero.itpub.net/406/67.htm">match()</a>，我将所有的节点名（即类的属性名）<a href="http://jasonhero.itpub.net/406/61.htm">join()</a>成一个大字符串，然后再用正则表达式匹配，一步就找出了想要的节点了。经测试，在三万节点里找30个节点对象耗时小于0.1秒！
    <li><strong>异步展示</strong> 再来讲一下节点字符串被解析之后转化成HTML元素的这一步操作。上面已经有过一个计算，表达1000节点的树的HTML字符量就有300K-600K之多，且这一步只能一个节点一个节点慢慢地生成，没有什么取巧的办法，想快点也只能是减小单个节点的HTML元素量罢，不过最快也得1-3秒每千节点呀，这也是没有法子的事，谁叫DOM的效率不高呢！总得想个什么法子吧，否则象5000节点量的树让使用者等上个半分钟一分钟的，谁也受不了呀！因此我想出异步展示这招：页面加载时并不立即生成所有节点的HTML元素，而是用户展开多少节点就生成多少节点，节点的生成发生在用户展开这个节点的时候。使用者在页面打开的时候并不会立即把所有的节点都一次全部展开，而是一级级地往下展开的，就象你查看windows注册表一样，想看哪级才会去展开哪一级，这样我就只需要在你展开那级的时候把这一级的节点转化成HTML即可，每次转化的节点只有几十分甚至只有几个而已，消除了使用者的等待时间。经过上面这几个环节，终于一棵实用性，效率，扩展性俱佳的WEB TreeView出世了。
    <li><strong>采用文字竖线</strong> 每个浏览器随着使用客户的不同，而总会产生不同的设置，其中有一项就是客户端设置每次访问都检查网页新版本，即客户端不缓存。这个设置对一般的应用来说问题不会很大，但是对于使用图片作为竖线的树来说随着节点总数的增多，图片的使用量也就跟着巨量增加，可能会使用几千甚至几万个小图片，每张图片是都很小，但量一大的话，将会严重影响树的快速展示，因此针对这种情况就得换一种模式来展现了，那就是文字竖线，用文字加样式就可以解决这个问题。我加了一个变量：MzTreeView.wordLine（布尔型，默认值为false），当网速过慢或者没有使用本地缓存时这个属性会自动设置成 true 而以文字代替图片完成竖线（注：Opera 浏览器不支持文字竖线模式），当然你也可以一开始就强行设置值为 true，这样树就会始终用文字竖线了。 </li>
</ul>
<dt>属性
<dd>MzTreeView 类的一些属性：
<div class="Article">
<table cellspacing="1" border="0">
    <tbody>
        <tr>
            <th>属性名</th>
            <th>类型</th>
            <th>属性的具体说明</th>
        </tr>
        <tr>
            <td>MzTreeView.nodes</td>
            <td>集合</td>
            <td>服务器端给树指定数据源时数据存放的对象，具体存放格式如：<br />
            MzTreeViewHandle.nodes["parentId_nodeId"] = "text: nodeText; icon: nodeIcon; url: nodeURL; ...";</td>
        </tr>
        <tr>
            <td>MzTreeView.url</td>
            <td>地址字符串</td>
            <td>可读写，树缺省的URL，默认值是 #</td>
        </tr>
        <tr>
            <td>MzTreeView.target</td>
            <td>目标框架名</td>
            <td>可读写，树缺省的链接target，默认值是 _self</td>
        </tr>
        <tr>
            <td>MzTreeView.name</td>
            <td>字符</td>
            <td>只读，树的实例名，同树实例化时作为参数传入(大小写敏感)：<br />
            var Tree = new MzTreeView("Tree");</td>
        </tr>
        <tr>
            <td>MzTreeView.currentNode</td>
            <td>树节点</td>
            <td>只读，树当前得到焦点的节点对象</td>
        </tr>
        <tr>
            <td>MzTreeView.icons</td>
            <td>集合</td>
            <td>树所使用的所有图标存放</td>
        </tr>
        <tr>
            <td>MzTreeView.iconsExpand</td>
            <td>集合</td>
            <td>树里展开状态的图标存放</td>
        </tr>
        <tr>
            <td>MzTreeView.colors</td>
            <td>集合</td>
            <td>树里使用到的几个颜色存放</td>
        </tr>
    </tbody>
</table>
</div>
<br />
MzTreeView 在客户端的节点所拥有的属性：
<div class="Article">
<table cellspacing="1" border="0">
    <tbody>
        <tr>
            <th>属性名</th>
            <th>属性的具体说明</th>
        </tr>
        <tr>
            <td>node.id</td>
            <td>数字文本，节点的ID</td>
        </tr>
        <tr>
            <td>node.parentId</td>
            <td>数字文本，节点对应的父节点ID</td>
        </tr>
        <tr>
            <td>node.text</td>
            <td>文本，节点的显示文本</td>
        </tr>
        <tr>
            <td>node.hint</td>
            <td>文本，节点的注释说明</td>
        </tr>
        <tr>
            <td>node.icon</td>
            <td>文本，节点对应的图标</td>
        </tr>
        <tr>
            <td>node.path</td>
            <td>文本，节点在树里的绝对路径：0_1_10_34</td>
        </tr>
        <tr>
            <td>node.url</td>
            <td>文本，该节点的 URL</td>
        </tr>
        <tr>
            <td>node.target</td>
            <td>文本，该节点链接的目标框架名</td>
        </tr>
        <tr>
            <td>node.data</td>
            <td>文本，该节点所挂载的数据</td>
        </tr>
        <tr>
            <td>node.method</td>
            <td>文本，该节点的点击对应处理语句</td>
        </tr>
        <tr>
            <td>node.parentNode</td>
            <td>对象，节点的父节点对象</td>
        </tr>
        <tr>
            <td>node.childNodes</td>
            <td>数组，包含节点下所有子节点的数组</td>
        </tr>
        <tr>
            <td>node.sourceIndex</td>
            <td>文本，服务器给予的数据里对象的 parentId_nodeId 的组合字符串</td>
        </tr>
        <tr>
            <td>node.hasChild</td>
            <td>布尔值，指该节点是否有子节点</td>
        </tr>
        <tr>
            <td>node.isLoad</td>
            <td>布尔值，本节点的子节点数据是否已经在客户端初始化</td>
        </tr>
        <tr>
            <td>node.isExpand</td>
            <td>布尔值，节点的展开状态</td>
        </tr>
    </tbody>
</table>
</div>
<dt>方法
<dd>MzTreeView 类的一些方法：
<div class="Article">
<table cellspacing="1" border="0">
    <tbody>
        <tr>
            <th>方法名</th>
            <th>方法的具体说明</th>
        </tr>
        <tr>
            <td>MzTreeView.toString()</td>
            <td>类的默认初始运行</td>
        </tr>
        <tr>
            <td>MzTreeView.buildNode(id)</td>
            <td>将该节点的所有下级子节点转换成 HTML 并在网页上体现出来</td>
        </tr>
        <tr>
            <td>MzTreeView.nodeToHTML(node, AtEnd)</td>
            <td>将 node 转换成 HTML</td>
        </tr>
        <tr>
            <td>MzTreeView.load(id)</td>
            <td>从数据源里加载当前节点下的所有子节点</td>
        </tr>
        <tr>
            <td>MzTreeView.nodeInit(sourceIndex, parentId)</td>
            <td>节点的信息初始，从数据源到客户端完整节点的转化</td>
        </tr>
        <tr>
            <td>MzTreeView.focus(id)</td>
            <td>聚集到某个节点上</td>
        </tr>
        <tr>
            <td>MzTreeView.expand(id[, sureExpand])</td>
            <td>展开节点（包含下级子节点数据的加载初始化）</td>
        </tr>
        <tr>
            <td>MzTreeView.setIconPath(path)</td>
            <td>给节点图片设置正确的路径</td>
        </tr>
        <tr>
            <td>MzTreeView.nodeClick(id)</td>
            <td>节点链接点击时同时被触发的点击事件处理方法</td>
        </tr>
        <tr>
            <td>MzTreeView.upperNode()</td>
            <td>跳转到当前聚集节点的父级节点</td>
        </tr>
        <tr>
            <td>MzTreeView.lowerNode()</td>
            <td>跳转到当前聚集节点的子级节点</td>
        </tr>
        <tr>
            <td>MzTreeView.pervNode()</td>
            <td>跳转到当前聚集节点的上一节点</td>
        </tr>
        <tr>
            <td>MzTreeView.nextNode()</td>
            <td>跳转到当前聚集节点的下一节点</td>
        </tr>
        <tr>
            <td>MzTreeView.expandAll()</td>
            <td>展开所有的树点，在总节点量大于500时这步操作将会比较耗时</td>
        </tr>
    </tbody>
</table>
</div>
<dt>示例
<dd class="exemple">
<pre class="Code">&lt;script language="JavaScript"
src="http://www.meizz.com/Web/Plugs/MzTreeView10.js"&gt;&lt;/script&gt;
&lt;base href="http://www.meizz.com/Web/"&gt;
&lt;style&gt;
A.MzTreeview
{
font-size: 9pt;
padding-left: 3px;
}
&lt;/style&gt;
&lt;script language="JavaScript"&gt;
var tree = new MzTreeView("tree");
tree.icons["property"] = "property.gif";
tree.icons["css"] = "collection.gif";
tree.icons["book"]  = "book.gif";
tree.iconsExpand["book"] = "bookopen.gif"; <span class="Note">//展开时对应的图片</span>
tree.setIconPath("http://www.meizz.com/Icons/TreeView/"); <span class="Note">//可用相对路径</span>
tree.nodes["0_1"] = "text:WEB 编程";
tree.nodes["1_100"] = "text:代码示例; data:id=100";
tree.nodes["1_200"] = "text:梅花雪脚本控件集; data:id=200";
tree.nodes["1_310"] = "text:CSS; icon:css; data:id=310";
tree.nodes["1_320"] = "text:DHTML; data:id=320";
tree.nodes["1_300"] = "text:HTML; data:id=300";
tree.nodes["1_400"] = "text:JavaScript; icon:book; data:id=400";
tree.nodes["320_322"] = "text:属性; icon: property; data:id=322";
tree.nodes["320_323"] = "text:方法; data:id=323";
tree.nodes["320_324"] = "text:事件; icon:event; data:id=324";
tree.nodes["320_325"] = "text:集合; data:id=325";
tree.nodes["400_407"] = "text:对象; data:id=407";
tree.nodes["400_406"] = "text:方法; data:id=406";
tree.nodes["400_408"] = "text:运算符; data:id=408";
tree.nodes["400_409"] = "text:属性; data:id=409";
tree.nodes["407_1140"] = "text:Date; url:Article.asp; data:id=140";
tree.nodes["406_1127"] = "text:toString; url:Article.asp; data:id=127";
tree.nodes["408_1239"] = "text:||; url:Article.asp; data:id=239";
tree.nodes["409_1163"] = "text:E;  url:Article.asp; data:id=163";
tree.setURL("Catalog.asp");
tree.setTarget("MzMain");
document.write(tree.toString());    <span class="Note">//亦可用 obj.innerHTML = tree.toString();</span>
&lt;/script&gt;
</pre>
<dd><br />
//MzTreeView1.0网页树类, 在实例化的时候请把实例名作参数传递进来 <br />
function MzTreeView(Tname) <br />
{ <br />
if(typeof(Tname) != "string" || Tname == "") <br />
throw(new Error(-1, '创建类实例的时候请把类实例的引用变量名传递进来！')); <br />
<br />
//【property】 <br />
this.url = "#"; <br />
this.target = "_self"; <br />
this.name = Tname; <br />
this.wordLine = false; <br />
this.currentNode = null; <br />
this.useArrow = true; <br />
this.nodes = {}; <br />
this.node = {}; <br />
this.names = ""; <br />
this._d = "x0f"; <br />
this.index = 0; <br />
this.divider = "_"; <br />
this.node["0"] = <br />
{ <br />
"id": "0", <br />
"path": "0", <br />
"isLoad": false, <br />
"childNodes": [], <br />
"childAppend": "", <br />
"sourceIndex": "0" <br />
}; <br />
<br />
this.colors = <br />
{ <br />
"highLight" : "#0A246A", <br />
"highLightText" : "#FFFFFF", <br />
"mouseOverBgColor" : "#D4D0C8" <br />
}; <br />
this.icons = { <br />
L0 : 'L0.gif', //┏ <br />
L1 : 'L1.gif', //┣ <br />
L2 : 'L2.gif', //┗ <br />
L3 : 'L3.gif', //━ <br />
L4 : 'L4.gif', //┃ <br />
PM0 : 'P0.gif', //＋┏ <br />
PM1 : 'P1.gif', //＋┣ <br />
PM2 : 'P2.gif', //＋┗ <br />
PM3 : 'P3.gif', //＋━ <br />
empty : 'L5.gif', //空白图 <br />
root : 'root.gif', //缺省的根节点图标 <br />
folder : 'folder.gif', //缺省的文件夹图标 <br />
file : 'file.gif', //缺省的文件图标 <br />
exit : 'exit.gif' <br />
}; <br />
this.iconsExpand = { //存放节点图片在展开时的对应图片 <br />
PM0 : 'M0.gif', //－┏ <br />
PM1 : 'M1.gif', //－┣ <br />
PM2 : 'M2.gif', //－┗ <br />
PM3 : 'M3.gif', //－━ <br />
folder : 'folderopen.gif', <br />
<br />
exit : 'exit.gif' <br />
}; <br />
<br />
//扩展 document.getElementById(id) 多浏览器兼容性 <br />
//id 要查找的对象 id <br />
this.getElementById = function(id) <br />
{ <br />
if (typeof(id) != "string" || id == "") return null; <br />
if (document.getElementById) return document.getElementById(id); <br />
if (document.all) return document.all(id); <br />
try {return eval(id);} catch(e){ return null;} <br />
} <br />
<br />
//MzTreeView 初始化入口函数 <br />
this.toString = function() <br />
{ <br />
this.browserCheck(); <br />
this.dataFormat(); <br />
this.setStyle(); <br />
this.load("0"); <br />
var rootCN = this.node["0"].childNodes; <br />
var str = "&lt;A id='"+ this.name +"_RootLink' href='#' style='DISPLAY: none'&gt;&lt;/A&gt;"; <br />
<br />
if(rootCN.length&gt;0) <br />
{ <br />
this.node["0"].hasChild = true; <br />
for(var i=0; i&lt;rootCN.length; i++) <br />
str += this.nodeToHTML(rootCN[i], i==rootCN.length-1); <br />
setTimeout(this.name +".expand('"+ rootCN[0].id +"', true); "+ <br />
this.name +".focusClientNode('"+ rootCN[0].id +"'); "+ this.name +".atRootIsEmpty()",10); <br />
} <br />
<br />
if (this.useArrow) //使用方向键控制跳转到上级下级父级子级节点 <br />
{ <br />
if (document.attachEvent) <br />
document.attachEvent("onkeydown", this.onkeydown); <br />
else if (document.addEventListener) <br />
document.addEventListener('keydown', this.onkeydown, false); <br />
} <br />
return "&lt;DIV class='MzTreeView' "+ <br />
"onclick='"+ this.name +".clickHandle(event)' "+ <br />
"ondblclick='"+ this.name +".dblClickHandle(event)' "+ <br />
"&gt;"+ str +"&lt;/DIV&gt;"; <br />
}; <br />
<br />
this.onkeydown= function(e) <br />
{ <br />
e = window.event || e; var key = e.keyCode || e.which; <br />
switch(key) <br />
{ <br />
case 37 : eval(Tname).upperNode(); break; //Arrow left, shrink child node <br />
case 38 : eval(Tname).pervNode(); break; //Arrow up <br />
case 39 : eval(Tname).lowerNode(); break; //Arrow right, expand child node <br />
case 40 : eval(Tname).nextNode(); break; //Arrow down <br />
} <br />
}; <br />
} <br />
<br />
//浏览器类型及版本检测 <br />
MzTreeView.prototype.browserCheck = function() <br />
{ <br />
var ua = window.navigator.userAgent.toLowerCase(), bname; <br />
if(/msie/i.test(ua)) <br />
{ <br />
this.navigator = /opera/i.test(ua) ? "opera" : ""; <br />
if(!this.navigator) this.navigator = "msie"; <br />
} <br />
else if(/gecko/i.test(ua)) <br />
{ <br />
var vendor = window.navigator.vendor.toLowerCase(); <br />
if(vendor == "firefox") this.navigator = "firefox"; <br />
else if(vendor == "netscape") this.navigator = "netscape"; <br />
else if(vendor == "") this.navigator = "mozilla"; <br />
} <br />
else this.navigator = "msie"; <br />
if(window.opera) this.wordLine = false; <br />
}; <br />
<br />
//给 TreeView 树加上样式设置 <br />
MzTreeView.prototype.setStyle = function() <br />
{ <br />
/* <br />
width: 16px; <br />
height: 16px; <br />
width: 20px; <br />
height: 20px; <br />
*/ <br />
var style = "&lt;style&gt;"+ <br />
"DIV.MzTreeView DIV IMG{border: 0px solid #FFFFFF;}"+ <br />
"DIV.MzTreeView DIV SPAN IMG{border: 0px solid #FFFFFF;}"; <br />
if(this.wordLine) <br />
{ <br />
style +=" <br />
DIV.MzTreeView DIV <br />
{ <br />
height: 20px;"+ <br />
(this.navigator=="firefox" ? "line-height: 20px;" : "" ) + <br />
(this.navigator=="netscape" ? "" : "overflow: hidden;" ) +" <br />
} <br />
DIV.MzTreeView DIV SPAN <br />
{ <br />
vertical-align: middle; font-size: 21px; height: 20px; color: #D4D0C8; cursor: default; <br />
} <br />
DIV.MzTreeView DIV SPAN.pm <br />
{ <br />
width: "+ (this.navigator=="msie"||this.navigator=="opera" ? "11" : "9") +"px; <br />
height: "+ (this.navigator=="netscape"?"9":(this.navigator=="firefox"?"10":"11")) +"px; <br />
font-size: 7pt; <br />
overflow: hidden; <br />
margin-left: -16px; <br />
margin-right: 5px; <br />
color: #000080; <br />
vertical-align: middle; <br />
border: 1px solid #D4D0C8; <br />
cursor: "+ (this.navigator=="msie" ? "hand" : "pointer") +"; <br />
padding: 0 2px 0 2px; <br />
text-align: center; <br />
background-color: #F0F0F0; <br />
}"; <br />
} <br />
style += "&lt;/style&gt;"; <br />
document.write(style); <br />
}; <br />
<br />
//当根节点为空的时候做的处理 <br />
MzTreeView.prototype.atRootIsEmpty = function() <br />
{ <br />
var RCN = this.node["0"].childNodes; <br />
for(var i=0; i&lt;RCN.length; i++) <br />
{ <br />
if(!RCN[i].isLoad) this.expand(RCN[i].id); <br />
if (RCN[i].text=="") <br />
{ <br />
var node = RCN[i].childNodes[0], HCN = node.hasChild; <br />
if(this.wordLine) <br />
{ <br />
var span = this.getElementById(this.name +"_tree_"+ node.id); <br />
span = span.childNodes[0].childNodes[0].childNodes[0]; <br />
span.innerHTML = RCN[i].childNodes.length&gt;1 ? "┌" : "─"; <br />
} <br />
else <br />
{ <br />
node.iconExpand = RCN[i].childNodes.length&gt;1 ? HCN ? "PM0" : "L0" : HCN ? "PM3" : "L3" <br />
this.getElementById(this.name +"_expand_"+ node.id).src = this.icons[node.iconExpand].src; <br />
} <br />
} <br />
} <br />
}; <br />
//初始化数据源里的数据以便后面的快速检索 <br />
MzTreeView.prototype.dataFormat = function() <br />
{ <br />
var a = new Array(); <br />
for (var id in this.nodes) a[a.length] = id; <br />
this.names = a.join(this._d + this._d); <br />
this.totalNode = a.length; a = null; <br />
}; <br />
<br />
//在数据源检索所需的数据节点 <br />
//id 客户端节点对应的id <br />
MzTreeView.prototype.load = function(id) <br />
{ <br />
var node = this.node[id], d = this.divider, _d = this._d; <br />
var sid = node.sourceIndex.substr(node.sourceIndex.indexOf(d) + d.length); <br />
var reg = new RegExp("(^|"+_d+")"+ sid +d+"[^"+_d+d +"]+("+_d+"|$)", "g"); <br />
var cns = this.names.match(reg), tcn = this.node[id].childNodes; if (cns){ <br />
reg = new RegExp(_d, "g"); for (var i=0; i&lt;cns.length; i++) <br />
tcn[tcn.length] = this.nodeInit(cns[i].replace(reg, ""), id); } <br />
node.isLoad = true; <br />
}; <br />
<br />
//初始化节点信息, 根据 this.nodes 数据源生成节点的详细信息 <br />
//sourceIndex 数据源中的父子节点组合的字符串 0_1 <br />
//parentId 当前树节点在客户端的父节点的 id <br />
MzTreeView.prototype.nodeInit = function(sourceIndex, parentId) <br />
{ <br />
this.index++; <br />
var source= this.nodes[sourceIndex], d = this.divider; <br />
var text = this.getAttribute(source, "text"); <br />
var hint = this.getAttribute(source, "hint"); <br />
var sid = sourceIndex.substr(sourceIndex.indexOf(d) + d.length); <br />
this.node[this.index] = <br />
{ <br />
"id" : this.index, <br />
"text" : text, <br />
"hint" : hint ? hint : text, <br />
"icon" : this.getAttribute(source, "icon"), <br />
"path" : this.node[parentId].path + d + this.index, <br />
"isLoad": false, <br />
"isExpand": false, <br />
"parentId": parentId, <br />
"parentNode": this.node[parentId], <br />
"sourceIndex" : sourceIndex, <br />
"childAppend" : "" <br />
}; <br />
this.nodes[sourceIndex] = "index:"+ this.index +";"+ source; <br />
this.node[this.index].hasChild = this.names.indexOf(this._d + sid + d)&gt;-1; <br />
if(this.node[this.index].hasChild) this.node[this.index].childNodes = []; <br />
return this.node[this.index]; <br />
}; <br />
<br />
//从XML格式字符串里提取信息 <br />
//source 数据源里的节点信息字符串(以后可以扩展对XML的支持) <br />
//name 要提取的属性名 <br />
MzTreeView.prototype.getAttribute = function(source, name) <br />
{ <br />
var reg = new RegExp("(^|;|s)"+ name +"s*:s*([^;]*)(s|;|$)", "i"); <br />
if (reg.test(source)) return RegExp.$2.replace(/[x0f]/g, ";"); return ""; <br />
}; <br />
<br />
//根据节点的详细信息生成HTML <br />
//node 树在客户端的节点对象 <br />
//AtEnd 布尔值 当前要转换的这个节点是否为父节点的子节点集中的最后一项 <br />
MzTreeView.prototype.nodeToHTML = function(node, AtEnd) <br />
{ <br />
var source = this.nodes[node.sourceIndex]; <br />
var target = this.getAttribute(source, "target"); <br />
var data = this.getAttribute(source, "data"); <br />
var url = this.getAttribute(source, "url"); <br />
if(!url) url = this.url; <br />
if(data) url += (url.indexOf("?")==-1?"?":"&amp;") + data; <br />
if(!target) target = this.target; <br />
<br />
var id = node.id; <br />
var HCN = node.hasChild, isRoot = node.parentId=="0"; <br />
if(isRoot &amp;&amp; node.icon=="") node.icon = "root"; <br />
if(node.icon=="" || typeof(this.icons[node.icon])=="undefined") <br />
node.icon = HCN ? "folder" : "file"; <br />
node.iconExpand = AtEnd ? "└" : "├"; <br />
<br />
var HTML = "&lt;DIV noWrap='True'&gt;&lt;NOBR&gt;"; <br />
if(!isRoot) <br />
{ <br />
node.childAppend = node.parentNode.childAppend + (AtEnd ? "　" : "│"); <br />
if(this.wordLine) <br />
{ <br />
HTML += "&lt;SPAN&gt;"+ node.parentNode.childAppend + (AtEnd ? "└" : "├") +"&lt;/SPAN&gt;"; <br />
if(HCN) HTML += "&lt;SPAN class='pm' id='"+ this.name +"_expand_"+ id +"'&gt;+&lt;/SPAN&gt;"; <br />
} <br />
else <br />
{ <br />
node.iconExpand = HCN ? AtEnd ? "PM2" : "PM1" : AtEnd ? "L2" : "L1"; <br />
HTML += "&lt;SPAN&gt;"+ this.word2image(node.parentNode.childAppend) +"&lt;IMG "+ <br />
"align='absmiddle' id='"+ this.name +"_expand_"+ id +"' "+ <br />
"src='"+ this.icons[node.iconExpand].src +"' style='cursor: "+ (!node.hasChild ? "": <br />
(this.navigator=="msie"||this.navigator=="opera"? "hand" : "pointer")) +"'&gt;&lt;/SPAN&gt;"; <br />
} <br />
} <br />
HTML += "&lt;IMG "+ <br />
"align='absMiddle' "+ <br />
"id='"+ this.name +"_icon_"+ id +"' "+ <br />
"src='"+ this.icons[node.icon].src +"'&gt;&lt;A "+ <br />
"class='MzTreeview' hideFocus "+ <br />
"id='"+ this.name +"_link_"+ id +"' "+ <br />
"href='"+ url +"' "+ <br />
"target='"+ target +"' "+ <br />
"title='"+ node.hint +"' "+ <br />
"onfocus=""+ this.name +".focusLink('"+ id +"')" "+ <br />
"onclick="return "+ this.name +".nodeClick('"+ id +"')"&gt;"+ node.text + <br />
"&lt;/A&gt;&lt;/NOBR&gt;&lt;/DIV&gt;"; <br />
if(isRoot &amp;&amp; node.text=="") HTML = ""; <br />
<br />
HTML = "rn&lt;SPAN id='"+ this.name +"_tree_"+ id +"'&gt;"+ HTML <br />
HTML +="&lt;SPAN style='DISPLAY: none'&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;"; <br />
return HTML; <br />
}; <br />
<br />
//在使用图片的时候对 node.childAppend 的转换 <br />
MzTreeView.prototype.word2image = function(word) <br />
{ <br />
var str = ""; <br />
for(var i=0; i&lt;word.length; i++) <br />
{ <br />
var img = ""; <br />
switch (word.charAt(i)) <br />
{ <br />
case "│" : img = "L4"; break; <br />
case "└" : img = "L2"; break; <br />
case "　" : img = "empty"; break; <br />
case "├" : img = "L1"; break; <br />
case "─" : img = "L3"; break; <br />
case "┌" : img = "L0"; break; <br />
} <br />
if(img!="") <br />
str += "&lt;IMG align='absMiddle' src='"+ this.icons[img].src +"' height='20'&gt;"; <br />
} <br />
return str; <br />
} <br />
<br />
<br />
//将某个节点下的所有子节点转化成详细的&lt;HTML&gt;元素表达 <br />
//id 树的客户端节点 id <br />
MzTreeView.prototype.buildNode = function(id) <br />
{ <br />
if(this.node[id].hasChild) <br />
{ <br />
var tcn = this.node[id].childNodes, str = ""; <br />
for (var i=0; i&lt;tcn.length; i++) <br />
str += this.nodeToHTML(tcn[i], i==tcn.length-1); <br />
var temp = this.getElementById(this.name +"_tree_"+ id).childNodes; <br />
temp[temp.length-1].innerHTML = str; <br />
} <br />
}; <br />
<br />
//聚集到客户端生成的某个节点上 <br />
//id 客户端树节点的id <br />
MzTreeView.prototype.focusClientNode = function(id) <br />
{ <br />
if(!this.currentNode) this.currentNode=this.node["0"]; <br />
<br />
var a = this.getElementById(this.name +"_link_"+ id); if(a){ a.focus(); <br />
var link = this.getElementById(this.name +"_link_"+ this.currentNode.id); <br />
if(link)with(link.style){color=""; backgroundColor="";} <br />
with(a.style){color = this.colors.highLightText; <br />
backgroundColor = this.colors.highLight;} <br />
this.currentNode= this.node[id];} <br />
}; <br />
<br />
//焦点聚集到树里的节点链接时的处理 <br />
//id 客户端节点 id <br />
MzTreeView.prototype.focusLink= function(id) <br />
{ <br />
if(this.currentNode &amp;&amp; this.currentNode.id==id) return; <br />
this.focusClientNode(id); <br />
}; <br />
<br />
//点击展开树节点的对应方法 <br />
MzTreeView.prototype.expand = function(id, sureExpand) <br />
{ <br />
var node = this.node[id]; <br />
if (sureExpand &amp;&amp; node.isExpand) return; <br />
if (!node.hasChild) return; <br />
var area = this.getElementById(this.name +"_tree_"+ id); <br />
if (area) area = area.childNodes[area.childNodes.length-1]; <br />
if (area) <br />
{ <br />
var icon = this.icons[node.icon]; <br />
var iconE = this.iconsExpand[node.icon]; <br />
var Bool = node.isExpand = sureExpand || area.style.display == "none"; <br />
var img = this.getElementById(this.name +"_icon_"+ id); <br />
if (img) img.src = !Bool ? icon.src :typeof(iconE)=="undefined" ? icon.src : iconE.src; <br />
var exp = this.icons[node.iconExpand]; <br />
var expE = this.iconsExpand[node.iconExpand]; <br />
var expand= this.getElementById(this.name +"_expand_"+ id); <br />
if (expand) <br />
{ <br />
if(this.wordLine) expand.innerHTML = !Bool ? "+" : "-"; <br />
else expand.src = !Bool ? exp.src : typeof(expE) =="undefined" ? exp.src : expE.src; <br />
} <br />
if(!Bool &amp;&amp; this.currentNode.path.indexOf(node.path)==0 &amp;&amp; this.currentNode.id!=id) <br />
{ <br />
try{this.getElementById(this.name +"_link_"+ id).click();} <br />
catch(e){this.focusClientNode(id);} <br />
} <br />
area.style.display = !Bool ? "none" : "block";//(this.navigator=="netscape" ? "block" : ""); <br />
if(!node.isLoad) <br />
{ <br />
this.load(id); <br />
if(node.id=="0") return; <br />
//当子节点过多时, 给用户一个正在加载的提示语句 <br />
if(node.hasChild &amp;&amp; node.childNodes.length&gt;200) <br />
{ <br />
setTimeout(this.name +".buildNode('"+ id +"')", 1); <br />
var temp = this.getElementById(this.name +"_tree_"+ id).childNodes; <br />
temp[temp.length-1].innerHTML = "&lt;DIV noWrap&gt;&lt;NOBR&gt;&lt;SPAN&gt;"+ (this.wordLine ? <br />
node.childAppend +"└" : this.word2image(node.childAppend +"└")) +"&lt;/SPAN&gt;"+ <br />
"&lt;IMG border='0' height='16' align='absmiddle' src='"+this.icons["file"].src+"'&gt;"+ <br />
"&lt;A style='background-Color: "+ this.colors.highLight +"; color: "+ <br />
this.colors.highLightText +"; font-size: 9pt'&gt;请稍候...&lt;/A&gt;&lt;/NOBR&gt;&lt;/DIV&gt;"; <br />
} <br />
else this.buildNode(id); <br />
} <br />
} <br />
}; <br />
<br />
//节点链接单击事件处理方法 <br />
//id 客户端树节点的 id <br />
MzTreeView.prototype.nodeClick = function(id) <br />
{ <br />
var source = this.nodes[this.node[id].sourceIndex]; <br />
eval(this.getAttribute(source, "method")); <br />
return !(!this.getAttribute(source, "url") &amp;&amp; this.url=="#"); <br />
}; <br />
<br />
//为配合系统初始聚集某节点而写的函数, 得到某节点在数据源里的路径 <br />
//sourceId 数据源里的节点 id <br />
MzTreeView.prototype.getPath= function(sourceId) <br />
{ <br />
<br />
Array.prototype.indexOf = function(item) <br />
{ <br />
for(var i=0; i&lt;this.length; i++) <br />
{ <br />
if(this[i]==item) return i; <br />
} <br />
return -1; <br />
}; <br />
var _d = this._d, d = this.divider; <br />
var A = new Array(), id=sourceId; A[0] = id; <br />
while(id!="0" &amp;&amp; id!="") <br />
{ <br />
var str = "(^|"+_d+")([^"+_d+d+"]+"+d+ id +")("+_d+"|$)"; <br />
if (new RegExp(str).test(this.names)) <br />
{ <br />
id = RegExp.$2.substring(0, RegExp.$2.indexOf(d)); <br />
if(A.indexOf(id)&gt;-1) break; <br />
A[A.length] = id; <br />
} <br />
else break; <br />
} <br />
return A.reverse(); <br />
}; <br />
<br />
//在源代码里指定 MzTreeView 初始聚集到某个节点 <br />
//sourceId 节点在数据源里的 id <br />
MzTreeView.prototype.focus = function(sourceId, defer) <br />
{ <br />
if (!defer) <br />
{ <br />
setTimeout(this.name +".focus('"+ sourceId +"', true)", 100); <br />
return; <br />
} <br />
var path = this.getPath(sourceId); <br />
if(path[0]!="0") <br />
{ <br />
alert("节点 "+ sourceId +" 没有正确的挂靠有效树节点上！rn"+ <br />
"节点 id 序列 = "+ path.join(this.divider)); <br />
return; <br />
} <br />
var root = this.node["0"], len = path.length; <br />
for(var i=1; i&lt;len; i++) <br />
{ <br />
if(root.hasChild) <br />
{ <br />
var sourceIndex= path[i-1] + this.divider + path[i]; <br />
for (var k=0; k&lt;root.childNodes.length; k++) <br />
{ <br />
if (root.childNodes[k].sourceIndex == sourceIndex) <br />
{ <br />
root = root.childNodes[k]; <br />
if(i&lt;len - 1) this.expand(root.id, true); <br />
else this.focusClientNode(root.id); <br />
break; <br />
} <br />
} <br />
} <br />
} <br />
}; <br />
<br />
//树的单击事件处理函数 <br />
MzTreeView.prototype.clickHandle = function(e) <br />
{ <br />
e = window.event || e; e = e.srcElement || e.target; <br />
//alert(e.tagName) <br />
switch(e.tagName) <br />
{ <br />
case "IMG" : <br />
if(e.id) <br />
{ <br />
if(e.id.indexOf(this.name +"_icon_")==0) <br />
this.focusClientNode(e.id.substr(e.id.lastIndexOf("_") + 1)); <br />
else if (e.id.indexOf(this.name +"_expand_")==0) <br />
this.expand(e.id.substr(e.id.lastIndexOf("_") + 1)); <br />
} <br />
break; <br />
case "A" : <br />
if(e.id) this.focusClientNode(e.id.substr(e.id.lastIndexOf("_") + 1)); <br />
break; <br />
case "SPAN" : <br />
if(e.className=="pm") <br />
this.expand(e.id.substr(e.id.lastIndexOf("_") + 1)); <br />
break; <br />
default : <br />
if(this.navigator=="netscape") e = e.parentNode; <br />
if(e.tagName=="SPAN" &amp;&amp; e.className=="pm") <br />
this.expand(e.id.substr(e.id.lastIndexOf("_") + 1)); <br />
break; <br />
} <br />
}; <br />
<br />
//MzTreeView 双击事件的处理函数 <br />
MzTreeView.prototype.dblClickHandle = function(e) <br />
{ <br />
e = window.event || e; e = e.srcElement || e.target; <br />
if((e.tagName=="A" || e.tagName=="IMG")&amp;&amp; e.id) <br />
{ <br />
var id = e.id.substr(e.id.lastIndexOf("_") + 1); <br />
if(this.node[id].hasChild) this.expand(id); <br />
} <br />
}; <br />
<br />
//回到树当前节点的父层节点 <br />
MzTreeView.prototype.upperNode = function() <br />
{ <br />
if(!this.currentNode) return; <br />
if(this.currentNode.id=="0" || this.currentNode.parentId=="0") return; <br />
if (this.currentNode.hasChild &amp;&amp; this.currentNode.isExpand) <br />
this.expand(this.currentNode.id, false); <br />
else this.focusClientNode(this.currentNode.parentId); <br />
}; <br />
<br />
//展开当前节点并 <br />
MzTreeView.prototype.lowerNode = function() <br />
{ <br />
if (!this.currentNode) this.currentNode = this.node["0"]; <br />
if (this.currentNode.hasChild) <br />
{ <br />
if (this.currentNode.isExpand) <br />
this.focusClientNode(this.currentNode.childNodes[0].id); <br />
else this.expand(this.currentNode.id, true); <br />
} <br />
} <br />
<br />
//聚集到树当前节点的上一节点 <br />
MzTreeView.prototype.pervNode = function() <br />
{ <br />
if(!this.currentNode) return; var e = this.currentNode; <br />
if(e.id=="0") return; var a = this.node[e.parentId].childNodes; <br />
for(var i=0; i&lt;a.length; i++){if(a[i].id==e.id){if(i&gt;0){e=a[i-1]; <br />
while(e.hasChild){this.expand(e.id, true); <br />
e = e.childNodes[e.childNodes.length - 1];} <br />
this.focusClientNode(e.id); return;} else { <br />
this.focusClientNode(e.parentId); return;}}} <br />
}; <br />
<br />
//聚集到树当前节点的下一节点 <br />
MzTreeView.prototype.nextNode = function() <br />
{ <br />
var e = this.currentNode; if(!e) e = this.node["0"]; <br />
if (e.hasChild){this.expand(e.id, true); <br />
this.focusClientNode(e.childNodes[0].id); return;} <br />
while(typeof(e.parentId)!="undefined"){ <br />
var a = this.node[e.parentId].childNodes; <br />
for(var i=0; i&lt;a.length; i++){ if(a[i].id==e.id){ <br />
if(i&lt;a.length-1){this.focusClientNode(a[i+1].id); return;} <br />
else e = this.node[e.parentId];}}} <br />
}; <br />
<br />
//展开树的所有节点 <br />
MzTreeView.prototype.expandAll = function() <br />
{ <br />
if(this.totalNode&gt;500) if( <br />
confirm("您是否要停止展开全部节点？rnrn节点过多！展开很耗时")) return; <br />
if(this.node["0"].childNodes.length==0) return; <br />
var e = this.node["0"].childNodes[0]; <br />
var isdo = t = false; <br />
while(e.id != "0") <br />
{ <br />
var p = this.node[e.parentId].childNodes, pn = p.length; <br />
if(p[pn-1].id==e.id &amp;&amp; (isdo || !e.hasChild)){e=this.node[e.parentId]; isdo = true;} <br />
else <br />
{ <br />
if(e.hasChild &amp;&amp; !isdo) <br />
{ <br />
this.expand(e.id, true), t = false; <br />
for(var i=0; i&lt;e.childNodes.length; i++) <br />
{ <br />
if(e.childNodes[i].hasChild){e = e.childNodes[i]; t = true; break;} <br />
} <br />
if(!t) isdo = true; <br />
} <br />
else <br />
{ <br />
isdo = false; <br />
for(var i=0; i&lt;pn; i++) <br />
{ <br />
if(p[i].id==e.id) {e = p[i+1]; break;} <br />
} <br />
} <br />
} <br />
} <br />
}; <br />
<br />
//本树将要用动的图片的字义及预载函数 <br />
//path 图片存放的路径名 <br />
MzTreeView.prototype.setIconPath = function(path) <br />
{ <br />
var k = 0, d = new Date().getTime(); <br />
for(var i in this.icons) <br />
{ <br />
var tmp = this.icons[i]; <br />
this.icons[i] = new Image(); <br />
this.icons[i].src = path + tmp; <br />
if(k==9 &amp;&amp; (new Date().getTime()-d)&gt;20) <br />
this.wordLine = true; k++; <br />
} <br />
for(var i in this.iconsExpand) <br />
{ <br />
var tmp = this.iconsExpand[i]; <br />
this.iconsExpand[i]=new Image(); <br />
this.iconsExpand[i].src = path + tmp; <br />
} <br />
}; <br />
<br />
//设置树的默认链接 <br />
//url 默认链接 若不设置, 其初始值为 # <br />
MzTreeView.prototype.setURL = function(url){this.url = url;}; <br />
<br />
//设置树的默认的目标框架名 target <br />
//target 目标框架名 若不设置, 其初始值为 _self <br />
MzTreeView.prototype.setTarget = function(target){this.target = target;}; <br />
// --&gt;
<div class="bo">一个简单的示例： <br />
<br />
&lt;script language="JavaScript" <br />
src="http://www.meizz.com/Web/Plugs/MzTreeView10.js"&gt;&lt;/script&gt; <br />
&lt;base href="http://www.meizz.com/Web/"&gt; <br />
&lt;style&gt; <br />
A.MzTreeview <br />
{ <br />
font-size: 9pt; <br />
padding-left: 3px; <br />
} <br />
&lt;/style&gt; <br />
&lt;script language="JavaScript"&gt; <br />
var tree = new MzTreeView("tree"); <br />
<br />
tree.icons["property"] = "property.gif"; <br />
tree.icons["css"] = "collection.gif"; <br />
tree.icons["book"] = "book.gif"; <br />
tree.iconsExpand["book"] = "bookopen.gif"; //展开时对应的图片 <br />
<br />
tree.setIconPath("http://www.meizz.com/Icons/TreeView/"); //可用相对路径 <br />
<br />
tree.nodes["0_1"] = "text:WEB 编程"; <br />
tree.nodes["1_100"] = "text:代码示例; data:id=100"; <br />
tree.nodes["1_200"] = "text:梅花雪脚本控件集; data:id=200"; <br />
tree.nodes["1_310"] = "text:CSS; icon:css; data:id=310"; <br />
tree.nodes["1_320"] = "text:DHTML; data:id=320"; <br />
tree.nodes["1_300"] = "text:HTML; data:id=300"; <br />
tree.nodes["1_400"] = "text:JavaScript; icon:book; data:id=400"; <br />
tree.nodes["320_322"] = "text:属性; icon: property; data:id=322"; <br />
tree.nodes["320_323"] = "text:方法; data:id=323"; <br />
tree.nodes["320_324"] = "text:事件; icon:event; data:id=324"; <br />
tree.nodes["320_325"] = "text:集合; data:id=325"; <br />
tree.nodes["400_407"] = "text:对象; data:id=407"; <br />
tree.nodes["400_406"] = "text:方法; data:id=406"; <br />
tree.nodes["400_408"] = "text:运算符; data:id=408"; <br />
tree.nodes["400_409"] = "text:属性; data:id=409"; <br />
tree.nodes["407_1140"] = "text:Date; url:Article.asp; data:id=140"; <br />
tree.nodes["406_1127"] = "text:toString; url:Article.asp; data:id=127"; <br />
tree.nodes["408_1239"] = "text:||; url:Article.asp; data:id=239"; <br />
tree.nodes["409_1163"] = "text:E; url:Article.asp; data:id=163"; <br />
<br />
tree.setURL("Catalog.asp"); <br />
tree.setTarget("MzMain"); <br />
document.write(tree.toString()); //亦可用 obj.innerHTML = tree.toString(); <br />
&lt;/script&gt;</div>
</dd></div>
<img src ="http://www.blogjava.net/kennyr/aggbug/215979.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kennyr/" target="_blank">-南风</a> 2008-07-19 11:07 <a href="http://www.blogjava.net/kennyr/articles/215979.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MzTreeView+JQuery实现地区树选择</title><link>http://www.blogjava.net/kennyr/articles/215978.html</link><dc:creator>-南风</dc:creator><author>-南风</author><pubDate>Sat, 19 Jul 2008 03:06:00 GMT</pubDate><guid>http://www.blogjava.net/kennyr/articles/215978.html</guid><wfw:comment>http://www.blogjava.net/kennyr/comments/215978.html</wfw:comment><comments>http://www.blogjava.net/kennyr/articles/215978.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kennyr/comments/commentRss/215978.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kennyr/services/trackbacks/215978.html</trackback:ping><description><![CDATA[http://hideto.javaeye.com/blog/213195
<img src ="http://www.blogjava.net/kennyr/aggbug/215978.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kennyr/" target="_blank">-南风</a> 2008-07-19 11:06 <a href="http://www.blogjava.net/kennyr/articles/215978.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>页面树形控件dhtmlxTree、mztreeview及xtree比较分析</title><link>http://www.blogjava.net/kennyr/articles/215965.html</link><dc:creator>-南风</dc:creator><author>-南风</author><pubDate>Sat, 19 Jul 2008 02:38:00 GMT</pubDate><guid>http://www.blogjava.net/kennyr/articles/215965.html</guid><wfw:comment>http://www.blogjava.net/kennyr/comments/215965.html</wfw:comment><comments>http://www.blogjava.net/kennyr/articles/215965.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kennyr/comments/commentRss/215965.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kennyr/services/trackbacks/215965.html</trackback:ping><description><![CDATA[作者：王力猛 (wallimn)<br />
电邮：<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#119;&#97;&#108;&#108;&#105;&#109;&#110;&#64;&#115;&#111;&#104;&#117;&#46;&#99;&#111;&#109;">wallimn@sohu.com</a><br />
博客：<a href="http://wallimn.bokee.com/">http://wallimn.bokee.com</a><br />
　　　<a href="http://blog.csdn.net/wallimn">http://blog.csdn.net/wallimn</a><br />
时间：2006-11-21<br />
/***********本人原创，欢迎转载，转载请保留本人信息*************/<br />
　　这两天整B/S的东西要在网页上用树来展示层次结构，去网上找了找，找到三个：xtree、mztreeview10(梅花雪树)以及dhtmlxTree.花了一些时间对这三个东西进行了一下测试分析。<br />
　　1.dhtmxTree<br />
　　优点：功能非常强，尤其应对树是动态变化的情况，提供了大量的API：比如添加节点、修改节点标题样式及图标、CheckBox功能、节点的查找定位以及拖动，树数据是从特定格式的XML文件（或字符串）中装载。<br />
　　缺点：正因为功能非常强，所以效率有些低，当节点数达1700多的时候，IE会出&#8220;装载时间过长，是否继续等待&#8221;的提示，选继续装载，可以装载完成，但节点的展开非常的慢。<br />
　　2.mztreeview1.0<br />
　　优点：这个树还是很有特点的，它的数据是一次性加载、异步显示的，也没有对cookie进行任何的操作，效率很高，据官方称：MzTreeView 1.0 在节点量三万至五万以上非常具有优势。<br />
　　缺点：这个树好象不是设计用来满足节点动态变化这个需求的，应该主要设计用来展示结构层次定死了的树。树的加载是通过调用document.write()来实现的。<br />
　　3.xtree<br />
　　这个树跟2有些相似，但多了一个在cookie中保存状态的功能，刷新、前进又后退回去，不会改变树的节点展开、关闭形态，也就说树会保持外观形态。2和3的效率我没有进行测试，但分析应该是2强于3吧。xtree我有同事用，说效率还可以，比dtree强很多。<br />
　　结论：对要进行较多的操作，树是动态变化的，而节点数又不太多的时候，dhtmxTree是不二的选择；而树是静态不变的，不需要在COOKIE中保存状态，那就用mztreeview了，mztreeview应对节点多的静态树有相当大的优势；xtree是三个产品中唯一使用到cookie的，这是它的显著特点，有这个需求，当然选它了。<br />
　　我对dhtmlxTree进行了一点小改造，就是加了个在选中节点前添加节点的功能（原来只有添加为后面的同级节点或子节点的功能），这个应该是树节点添加操作中常见的功能，使用dhtmlxTree又需要这个功能的朋友请与我联系。
 <img src ="http://www.blogjava.net/kennyr/aggbug/215965.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kennyr/" target="_blank">-南风</a> 2008-07-19 10:38 <a href="http://www.blogjava.net/kennyr/articles/215965.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>