javascript dtree工作原理

http://programmerdigest.cn/2009/12/798.html

dTree 的工作原理

<html>
    <head>
        <link rel="StyleSheet" href="dtree.css" type="text/css" />
        <script type="text/javascript" src="dtree.js"></script>
    </head>
    <body>
        <script type="text/javascript">
        <!--
            d = new dTree( 'd' ) ; //创建树,名称为'd'
            d.add ( 0 ,-1 ,'根节点' ) ;
            d.add ( 1 ,0 ,'节点 1' ,'node1.html' ) ;
            d.add ( 2 ,0 ,'节点 2' ,'node2.html' ) ;
            d.add ( 3 ,1 ,'节点 1.1' ,'node1_1.html' ) ;
            d.add ( 4 ,3 ,'节点 1.1.1' ,'node1_1_1.html' ) ;
            document.write ( d) ;
            function show( )
            {
                alert ( d) ;
            }
        //-->
        </script>
        <input type="button" value="显示html" οnclick="show()">
    </body>
</html>


点击下方的“显示html”按钮,会在alert对话框中显示整个树的html代码


仔细观察,树中每个节点的html构造是相似的:

<!-- 根节点 -->
<div class ="dTreeNode" >
    <img id ="id0" src ="img/base.gif" alt ="" /> 根节点</a>
</div>
<div id ="dd0" class ="clip" style ="display:block;" >
    ......
</div>
<!-- 节点 1 -->
<div class ="dTreeNode" >
    <a href ="javascript: d.o(1);" > <img id ="jd1" src ="img/minus.gif" alt ="" /> </a>
    <img id ="id1" src ="img/folderopen.gif" alt ="" />
    <a href ="javascript: d.o(1);" class ="node" > 节点 1</a>
</div>
<div id ="dd1" class ="clip" style ="display:block;" >
    ......
</div>
<!-- 节点 1.1 -->
<div class ="dTreeNode" >
    <img src ="img/line.gif" alt ="" />
    <a href ="javascript: d.o(3);" > <img id ="jd3" src ="img/minusbottom.gif" alt ="" /> </a>
    <img id ="id3" src ="img/folderopen.gif" alt ="" />
    <a href ="javascript: d.o(3);" class ="node" > 节点 1.1</a>
</div>
<div id ="dd3" class ="clip" style ="display:block;" >
    ......
</div>
<!-- 节点 1.1.1 -->
<div class ="dTreeNode" >
    <img src ="img/line.gif" alt ="" />
    <img src ="img/empty.gif" alt ="" />
    <img src ="img/joinbottom.gif" alt ="" />
    <img id ="id4" src ="img/page.gif" alt ="" />
    <a id ="sd4" class ="node" href ="node1_1_1.html" onclick ="javascript: d.s(4);" > 节点 1.1.1</a>
</div>
<!-- 节点 2 -->
<div class ="dTreeNode" >
    <img src ="img/joinbottom.gif" alt ="" />
    <img id ="id2" src ="img/page.gif" alt ="" />
    <a id ="sd2" class ="node" href ="node2.html" onclick ="javascript: d.s(2);" > 节点 2</a>
</div>
每个节点由两个<div>组成,第一个div (class="dTreeNode")描述当前节点,如节点显示文字、节点图标、图标前的加减号、连线等;第二个div (class="clip")描述当前节点的子节点(包括子节点的子节点),注意div的样式 style="display:block;","block"表示显示div,也就是显示子节点,如果样式为 style="display:none;",则隐藏div,也就隐藏了子节点,d.o()函数控制display样式的变换,也就相应实现了子节点的打 开和关闭。

"节点 1.1.1" 和 "节点 2" 没有子节点,所以没有第二个<div>。


在dTree中,树中的节点是一次生成的,但在一些应用场景中,节点数非常大,比如我国的行政区划中省、市县两级的数量就超千个,一次性的生成 dTree树非常耗资源,速度也慢。针对这种情况需要“异步”构建树,比如在页面上先生成省、自治区的一级节点,当用鼠标点开某个“省”节点时,实时从后 台获得该省下级的市县节点。

下面就一步步的完成这个对dTree的改造需求。

改造原则

我在这里要说明的是:不建议对dTree大改,因为改的越多风险越大,毕竟我们只是dTree的使用者,而不是开发者,特别在项目时间紧、压力大的环境中,迅速打造一个能用、稳定的控件尤其重要。

创建一级节点

这里的行政区划不规范,和国家规定的有出入,但作为示例程序比较好理解,从我所在的省份“陕西省”开始,省的下级有“陕北”、“关中”、“陕南”三个子集。

d = new dTree(’d'); //创建树,名称为’d’
d.add(0,-1,’陕西省’);
d.add(1,0,’陕北’);
d.add(2,0,’关中’);
d.add(3,0,’陕南’);
document.write(d);
生成的页面显示:

 

在dTree中,如果一个节点没有子集,它的前面不会出现“+”图标,我们希望在红色标记处形有“+”或“-”图标,这样就可以动态的从后台获取他们的子集。查看d.add()函数的实现代码:

dTree.prototype.add = function(id, pid, name, url, title, target, icon, iconOpen, open) {
    //增加到节点数组的末尾
    this.aNodes[this.aNodes.length] = new Node(id, pid, name, url, title, target, icon, iconOpen, open);
};
在add函数中,new了一个节点对象,aNodes是dTree中的节点数组,下标“this.aNodes.length”是数组末尾的下一个,表示在数组最后增加一个节点。将上面的代码改动一下:

d = new dTree(’d');
d.add(0,-1,’陕西省’);

//陕北

var shanbei = new Node(1,0,’<input type=/"checkbox/" name=/"where/" value=/"1/">陕北’);
shanbei._hc = true; //有子节点
d.aNodes[d.aNodes.length] = shanbei; //加入到树
//关中
var guanzhong = new Node(2,0,’<input type=/"checkbox/" name=/"where/" value=/"2/">关中’);
guanzhong._hc = true;
d.aNodes[d.aNodes.length] = guanzhong;
//陕南
var shannan = new Node(3,0,’<input type=/"checkbox/" name=/"where/" value=/"3/">陕南’);
shannan._hc = true;
d.aNodes[d.aNodes.length] = shannan;

document.write(d);

先new出节点对象,将对象的”_hc”属性置为true,表示有子节点,形成的页面显示如下(手工点开了“关中”节点):

 

点击“显示html”按钮,观察一下树的html结构:

<div class ="dtree" >
    <div class ="dTreeNode" >
        <img id ="id0" src ="img/base.gif" alt ="" /> 陕西省</a>
    </div>
    <div id ="dd0" class ="clip" style ="display:block;" >
        <div class ="dTreeNode" >
            <a href ="javascript: d.o(1);" > <img id ="jd1" src ="img/plus.gif" alt ="" /> </a>
            <img id ="id1" src ="img/folder.gif" alt ="" />
            <a href ="javascript: d.o(1);" class ="node" > <input type ="checkbox" name ="where" value ="1" > 陕北</a>
        </div>
        <div id ="dd1" class ="clip" style ="display:none;" > </div>
        <div class ="dTreeNode" > <a href ="javascript: d.o(2);" >
            <img id ="jd2" src ="img/minus.gif" alt ="" /> </a>
            <img id ="id2" src ="img/folderopen.gif" alt ="" />
            <a href ="javascript: d.o(2);" class ="node" > <input type ="checkbox" name ="where" value ="2" > 关中</a>
        </div>
        <div id ="dd2" class ="clip" style ="display:block;" > </div>
        <div class ="dTreeNode" >
            <a href ="javascript: d.o(3);" > <img id ="jd3" src ="img/plusbottom.gif" alt ="" /> </a>
            <img id ="id3" src ="img/folder.gif" alt ="" />
            <a href ="javascript: d.o(3);" class ="node" > <input type ="checkbox" name ="where" value ="3" > 陕南</a>
        </div>
        <div id ="dd3" class ="clip" style ="display:none;" > </div>
    </div>
</div>
“关中”有子节点div标签,<div id=”dd2″ class=”clip” style=”display:block;”></div>,但没有内部子节点内容。

动态获取下级节点

节点的打开和关闭是由d.o()函数控制的,下来需要对d.o()函数做点小改动,先观察o函数的原始代码(我加上了注释):

//———————————
// dTree对象的o()方法
// 打开或关闭指定节点
// 参数id: 节点ID
//———————————
dTree.prototype.o = function(id) {
    //id对应的节点对象
    var cn = this.aNodes[id];
    //html变化
    this.nodeStatus(!cn._io, id, cn._ls);
    //open状态反转
    cn._io = !cn._io;
    //关闭同级别节点
    if (this.config.closeSameLevel) this.closeLevel(cn);
    //状态更新保存在cookies
    if (this.config.useCookies) this.updateCookie();
};
下面是改动后的代码:

//———————————
// dTree对象的o()方法
// 打开或关闭指定节点
// 参数id: 节点ID
//———————————
dTree.prototype.o = function(id) {
    //示例程序只处理“关中”的子集
    if (id == 2){
        //子节点标签, “关中”子节点div的id是"dd2"
        var subDIV = document.getElementById("dd" + id);

        //判断子节点标签是否有内容,如果没有内容就从“后台”动态获取,
        //如果有内容则跳过,这样只在第一次打开节点时获取“后台”数据。
        if(subDIV != null && !subDIV.hasChildNodes())
        {
            //一般通过Ajax从后台获取子集信息,示例程序省略了。
            //假定从后台获取“关中”的子节点信息为:
            //      有两个子节点:“西安”节点id=5,有子节点;“咸阳”id=6,无子节点(叶子节点)

            //构造西安节点
            var xian = new Node(5,id,’<input type=/"checkbox/" name=/"where/" value=/"5/">西 安’);
            xian._hc = true; //有子节点
            this.aNodes[this.aNodes.length] = xian; //加入到树

            //构造咸阳节点
            var xianyang = new Node(6,id,’<input type=/"checkbox/" name=/"where/" value=/"6/">咸阳’);
            xianyang._hc = false; //无子节点
            this.aNodes[this.aNodes.length] = xianyang; //加入到树
        }
    }

    //id对应的节点对象
    var cn = this.aNodes[id];
    //html变化
    this.nodeStatus(!cn._io, id, cn._ls);
    //open状态反转
    cn._io = !cn._io;
    //关闭同级别节点
    if (this.config.closeSameLevel) this.closeLevel(cn);
    //状态更新保存在cookies
    if (this.config.useCookies) this.updateCookie();
};
o函数中增加的的代码模拟了从后台获得“关中”子节点,在一般的应用中通常是通过Ajax技术来获取动态内容,Ajax的实现种类很多,所以这里只模拟而不演示具体的。

不论从后台通过何种技术来动态获取,获取信息必须要包括:

1. 子节点的ID
2. 子节点的名称
3. 子节点是否有下级

20-28行,根据从“后台”获得的子节点信息,在树中添加“西安”和“咸阳”两个节点,但遗憾的是,点开“关中”节点时并没有出现预想的状况,和o函数修改前没什么变化。

同步更新DOM

点击“显示html”按钮,在alret对话框中“关中”子节点的<div>中已经出现了“西安”和“咸阳”的标签代码,页面不响应是 因为dTree的实现是基于html的,而不是基于DOM的,当语句 document.write(d); 将树html输出给浏览器后,再去改变”d”的内容,浏览器是不响应的,要达到我们的目的,需要一点技巧:

<html>
<head>
<link rel="StyleSheet" href="dtree.css" type="text/css" />
<script type="text/javascript" src="dtree.js"></script>
<script type="text/javascript" >
<!–
function show( )
{
    alert ( d.toString ( ) ) ;
}
//–>
</script>
</head>
<body>
<div id="mydTree">
<script type="text/javascript" >
<!–
d = new dTree( ‘d’ ) ;
d.add ( 0 ,-1 ,‘陕西省’ ,null ,null ,null ,‘img/globe.gif’ ) ;

//陕北

var shanbei = new Node( 1 ,0 ,‘<input type=/” checkbox/” name=/” where/” value=/” 1/” >陕北’ ) ;
shanbei._hc = true ; //有子节点
d.aNodes [ d.aNodes .length ] = shanbei; //加入到树
//关中
var guanzhong = new Node( 2 ,0 ,‘<input type=/” checkbox/” name=/” where/” value=/” 2/” >关中’ ) ;
guanzhong._hc = true ;
d.aNodes [ d.aNodes .length ] = guanzhong;
//陕南
var shannan = new Node( 3 ,0 ,‘<input type=/” checkbox/” name=/” where/” value=/” 3/” >陕南’ ) ;
shannan._hc = true ;
d.aNodes [ d.aNodes .length ] = shannan;

document.write ( d) ;


//–>

</script>
</div>

<input type="button" value="显示html" οnclick="show()">

</body>
在dTree输出的外面包了一层div标签,就是那个 id=”mydTree” 的div标签,然后在o函数中增加一句:

            ……
            //构造咸阳节点
            var xianyang = new Node(6,id,’<input type=/"checkbox/" name=/"where/" value=/"6/">咸阳’);
            xianyang._hc = false; //无子节点
            this.aNodes[this.aNodes.length] = xianyang; //加入到树
           
            //同步修改DOM
            document.getElementById("mydTree").innerHTML = this.toString();
        }
    }

    //id对应的节点对象

    var cn = this.aNodes[id];
    ……

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值