javascript-TreeView父子联动效果保持节点状态一致


Posted in Javascript onAugust 12, 2007

我们大部分都用过TreeView控件,对这个控件的评价也是各式各样的,但是我觉得不论如何它是一个免费的开源的控件,所以我还是在用它。在刚接触ASP.NET的时候,记得需要做一个分配权限的权限树,当时只知道有这个树,经过一天的研究对其服务器端的行为基本以及搞清楚了,但是由于当时的js水平有限,所以对客户端的代码很畏惧,基本没有看过。
当时有这样一个要求:如果一个节点被选中则该节点的所有子节点都要选中,如果该节点的所有子节点取消选择则该节点也要取消选择(节点一致性),相反一样。
还有一个要求就是:如果可以实现三态树则更好(这个有点难,本文中不予讨论)。本文将详细介绍前面要求1。
        首先我们要庆幸微软的这个TreeView控件是开源的,不论是客户端代码还是服务器端代码您都可以轻松获得,可以去微软的网站上下载。在网上也见过一些讲述该问题的文章,他们大多是使用一个TreeView之外的js实现,我个人认为从面向对象的观点,该功能属于TreeView,所以没有理由将它分离出去,因此今天我将修改TreeView.htc来实现上面的功能。要想获得该文件(TreeView.htc)可以去微软的网站上下载之。
说实在的该功能曾经也困扰了我很久,一直想解决这个问题,但是一直没有时间来研究TreeView.htc中的代码,今天终于下决心搞定它。
        我们知道在TreeView的oncheck中需要激发该事件处理函数,这个函数很容易找到,可以在TreeView生成的客户度脚本中找到,代码片断如下:
oncheck="javascript: if (this.clickedNodeIndex != null) this.queueEvent('oncheck', this.clickedNodeIndex)"
        由此我们可以去htc(以后说的htc都指的是TreeView.htc),找到doCheckboxClick方法,只要看名字就知道它是干什么的(命名实在太重要了,否则在3000行代码中找某个函数真的很累)。
        该方法是当用户点击CheckBox的使用要处理的函数,函数如下所示:
        function doCheckboxClick(el){
            var checked = private_getAttribute(el,"checked")
            el.checked = !checked;
            var evt = createEventObject();
            evt.treeNodeIndex = getNodeIndex(el);
            g_nodeClicked = el;
            _tvevtCheck.fire(evt);
            setNodeState(el,el.checked);// maybe need el only,but I think it's safly
        }
        其中第一行、第二行以及最后一行是我添加的,第一二行是为了在页面回传以后checked属性无效时所做的修改,按照原来的方法在提交后el.checked是undefined,所以导致无法正确同步节点,如果读者有兴趣可以试一试。setNodeState函数,从名字上可以看出该函数是用来设置节点状态的,它将当前你选择的节点作为参数传递到函数内部。如注释中所说实际上你可以只传递el进去,而无需再传一个布尔值,不过我想这样传递可能更安全,不过没有关系,你觉得不爽可以修改:。
        下面看看setNodeState的函数体,该函数由两个方法组成,一个是设置所有孩子节点的状态,一个是设置该节点的父节点状态。代码如下:
        function  setNodeState(el,state){
            _setChildNode(el,state);
            _setParentNode(el,state);
        }
        为了可以设置当前节点的所有孩子节点是否和父节点(本节点)状态一至我们需要函数_setChildNode,同理为了使节点的父节点和该节点状态一至我们需要_setParentNode函数。两个函数都是递归函数,将会遍历所有的子节点和所有的父节点以及兄弟节点(为什么要遍历兄弟节点稍候再说),下面我们先看看遍历孩子节点的代码,代码如下所示:
        function  _setChildNode(el,state){
            var childNodes = el.children;
            if(childNodes.length > 0){// if has childs 
                for(var i = 0 ;i<=childNodes.length-1;i++){
                    private_setAttribute(childNodes[i],"Checked",state);
                    _saveCheckState(childNodes[i]);
                    _setChildNode(childNodes[i],state);
                }
            }
        }
        该函数先获得当前节点的所有子节点,这里可以直接使用TreeView提供的函数getChildren方法,而我使用的使html的原始方法。如果该节点存在子节点则遍历所有子节点,同时设置子节点的状态和当前节点的状态一致,_saveCheckState函数的作用稍候会介绍。private_setAttribute方法为TreeView提供的一个内部设置属性的方法(js没有private关键字,这里只是做说明而已),该方法将设置每一个节点的Checked属性为当前这个节点的状态。
        下面是如何设置父节点状态的代码:
         function  _setParentNode(el,state){
            var parentNode = el.parentElement;
            if(parentNode){
                if(!_checkSiblingdNode(el)){
                    private_setAttribute(parentNode,"Checked",state);
                    _saveCheckState(parentNode);
                    _setParentNode(parentNode,state);
                }
            }
        }
        该函数先获得其父节点,如果父节点存在则检查当前节点的兄弟节点,上面有提到了需要检查兄弟节点,这里检查兄弟节点的目的是:父节点的状态不是由当前节点一个节点控制的(这种情况只存在于当前节点没有兄弟节点的情况下),如果有其他兄弟是选中的,那么父节点是不能被取消了,这样将导致兄弟节点和父子节点不一致不一致。该函数里面也调用了_saveCheckState函数,在后面将介绍之。
下面的代码描述了如何检查兄弟节点的状态,代码如下:
        function _checkSiblingdNode(el){
            var parentNode = el.parentElement;// you can use getParentTreeNode function in this htc,but I like this usage.
            for(var i = 0;i<=parentNode.children.length-1;i++){
                if(el != parentNode.children[i]){
                    if(private_getAttribute(parentNode.children[i],"Checked")){
                        return true;
                    }
                }
            }
            return false;
        }
        正如注释所述,你可以使用getParentTreeNode方法来获得节点的父节点,但是我比较喜欢使用原始的方法:。这里将排除自己(if(el!=parentNode.children[i]))。
        有了上面的代码我们就可以做到客户端无刷新的父子节点一致的选择,那么我们现在来介绍一下_saveCheckState函数,如果没有该函数页面提交以后,刚才除了手工点击的节点以外其他的节点都不能保存状态。所以该函数的作用就是要保存所有节点的状态(主要是自动选择的节点),保证在回传之后树的状态依然存在。下面的代码描述了_saveCheckState函数,代码如下:
        function _saveCheckState(el){
            if(getNodeIndex(el))
                queueEvent('oncheck', getNodeIndex(el));
        }
        该方法首先检查当前节点的index是否有效,如果有效则保存状态。这里需要说一下queueEvent方法做了什么,代码我就不帖了,该函数的实际意义是将客户端的操作保存在一个名为__TreeView1_State__的隐藏域中,这样在回传的时候服务器端会根据该隐藏域,初始化树的状态。其中TreeView1是我在测试系统中TreeView的名字。
        最后的问题就是部署的问题了,因为修改了htc,所以在部署的时候需要替换原来的htc文件。
        如果有需要修改之后的TreeView.htc(格式化之后的),可以在CSDN上改我留言留下email。我的CSDN帐号是cuike519。
        希望微软可以早日将这个功能添加到TreeView控件中,最好也能实现多态的树结构。请浏览blog的相关评论,我会在评论中更新文章!

Javascript 相关文章推荐
javascript 的Document属性和方法集合
Jan 25 Javascript
javascript中方便增删改cookie的一个类
Oct 11 Javascript
jQuery在ul中显示某个li索引号的方法
Mar 17 Javascript
jQuery实现折叠、展开的菜单组效果代码
Sep 16 Javascript
分享JavaScript监听全部Ajax请求事件的方法
Aug 28 Javascript
yii form 表单提交之前JS在提交按钮的验证方法
Mar 15 Javascript
JavaScrpt的面向对象全面解析
May 09 Javascript
小程序测试后台服务的方法(ngrok)
Mar 08 Javascript
vue使用axios上传文件(FormData)的方法
Apr 14 Javascript
微信小程序实现蓝牙打印
Sep 23 Javascript
vue实现评价星星功能
Jun 30 Javascript
javascript实现随机抽奖功能
Dec 30 Javascript
TopList标签和JavaScript结合两例
Aug 12 #Javascript
Javascript-Mozilla和IE中的一个函数直接量的问题分析
Aug 12 #Javascript
IE和Mozilla的兼容性汇总event
Aug 12 #Javascript
收藏Javascript中常用的55个经典技巧
Aug 12 #Javascript
JavaScript-世界上误解最深的语言分析
Aug 12 #Javascript
用javascript实现兼容IE7的类库 IE7_0_9.zip提供下载
Aug 08 #Javascript
alixixi runcode.asp的代码不错的应用
Aug 08 #Javascript
You might like
基于CI框架的微信网页授权库示例
2016/11/25 PHP
thinkphp5.1框架模板赋值与变量输出示例
2020/05/25 PHP
jquery ready函数源代码研究
2009/12/06 Javascript
简单的Jquery全选功能
2013/11/07 Javascript
JS按字节截取字符长度实例
2013/11/20 Javascript
js控制table合并具体实现
2014/02/20 Javascript
javasctipt如何显示几分钟前、几天前等
2014/04/30 Javascript
浅谈页面装载js及性能分析方法
2014/12/09 Javascript
浅谈Javascript如何实现匀速运动
2014/12/19 Javascript
常用的jQuery前端技巧收集
2014/12/24 Javascript
JavaScript数据库TaffyDB用法实例分析
2015/07/27 Javascript
jquery easyui validatebox remote的使用详解
2016/11/09 Javascript
前端图片懒加载(lazyload)的实现方法(提高用户体验)
2017/08/21 Javascript
浅谈vue项目重构技术要点和总结
2018/01/23 Javascript
JS实现字符串翻转的方法分析
2018/08/31 Javascript
微信小程序实现吸顶特效
2020/01/08 Javascript
JS+HTML实现自定义上传图片按钮并显示图片功能的方法分析
2020/02/12 Javascript
vue 获取url参数、get参数返回数组的操作
2020/11/12 Javascript
[00:48]完美“圣”典2016风云人物:xiao8宣传片
2016/11/30 DOTA
Python计算程序运行时间的方法
2014/12/13 Python
详解Python程序与服务器连接的WSGI接口
2015/04/29 Python
Python脚本处理空格的方法
2016/08/08 Python
python http接口自动化脚本详解
2018/01/02 Python
解决pyttsx3无法封装的问题
2018/12/24 Python
flask应用部署到服务器的方法
2019/07/12 Python
python3中sys.argv的实例用法
2020/04/24 Python
Alba Moda瑞士网上商店:独家意大利时尚女装销售
2016/11/28 全球购物
美国知名保健品网站:LuckyVitamin(支持中文)
2017/08/09 全球购物
Europcar意大利:汽车租赁
2019/07/07 全球购物
关于安全的广播稿
2014/10/23 职场文书
中学生清明节演讲稿
2015/03/18 职场文书
女性健康知识讲座主持词
2015/07/04 职场文书
土木工程生产实习心得体会
2016/01/22 职场文书
《槐乡的孩子》教学反思
2016/02/20 职场文书
小学五年级(说明文3篇)
2019/08/13 职场文书
SQL中的连接查询详解
2022/06/21 SQL Server