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 相关文章推荐
超级退弹代码
Jul 07 Javascript
Table冻结表头示例代码
Aug 20 Javascript
javasciprt下jquery函数$.post执行无响应的解决方法
Mar 13 Javascript
JS实现横向拉伸动感伸缩菜单效果代码
Sep 04 Javascript
vue使用vue-cli快速创建工程
Jul 28 Javascript
在Vue中获取组件声明时的name属性方法
Sep 12 Javascript
微信小程序封装的HTTP请求示例【附升级版】
May 11 Javascript
利用百度echarts实现图表功能简单入门示例【附源码下载】
Jun 10 Javascript
JavaScript函数IIFE使用详解
Oct 21 Javascript
解决VUE双向绑定失效的问题
Oct 29 Javascript
Vue 打包体积优化方案小结
May 20 Javascript
详解Vue slot插槽
Nov 20 Vue.js
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
ThinkPHP采用模块和操作分析
2011/04/18 PHP
PhpMyAdmin出现export.php Missing parameter: what /export_type错误解决方法
2012/08/09 PHP
两千行代码的PHP学习笔记汇总
2014/10/05 PHP
laravel通过a标签从视图向控制器实现传值
2019/10/15 PHP
How to Auto Include a Javascript File
2007/02/02 Javascript
使用js 设置url参数
2013/07/08 Javascript
js实现网站最上边可关闭的浮动广告条代码
2015/09/04 Javascript
JavaScript数据结构与算法之栈与队列
2016/01/29 Javascript
AngularJS在IE8的不支持的解决方法
2016/05/13 Javascript
浅谈js中function的参数默认值
2017/02/20 Javascript
jQuery树控件zTree使用方法详解(一)
2017/02/28 Javascript
关于Node.js中Buffer的一些你可能不知道的用法
2017/03/28 Javascript
浅谈mint-ui loadmore组件注意的问题
2017/11/08 Javascript
微信小程序实现红包功能(后端PHP实现逻辑)
2018/07/11 Javascript
js实现简单选项卡功能
2020/03/23 Javascript
Vuejs+vue-router打包+Nginx配置的实例
2018/09/20 Javascript
VUE单页面切换动画代码(全网最好的切换效果)
2019/10/31 Javascript
Javascript实现单选框效果
2020/12/09 Javascript
浅谈numpy数组的几种排序方式
2017/12/15 Python
Python读取Excel表格,并同时画折线图和柱状图的方法
2018/10/14 Python
Opencv实现抠图背景图替换功能
2019/05/21 Python
selenium中get_cookies()和add_cookie()的用法详解
2020/01/06 Python
Python 一行代码能实现丧心病狂的功能
2020/01/18 Python
python中的socket实现ftp客户端和服务器收发文件及md5加密文件
2020/04/01 Python
jupyter 使用Pillow包显示图像时inline显示方式
2020/04/24 Python
分布式全文检索引擎ElasticSearch原理及使用实例
2020/11/14 Python
Python非单向递归函数如何返回全部结果
2020/12/18 Python
python 实现图片批量压缩的示例
2020/12/18 Python
详解Python模块化编程与装饰器
2021/01/16 Python
pycharm Tab键设置成4个空格的操作
2021/02/26 Python
html标签之Object和EMBED标签详解
2013/07/04 HTML / CSS
审计主管岗位职责
2014/01/31 职场文书
创建文明城市标语
2014/06/16 职场文书
七年级思品教学反思
2016/02/20 职场文书
企业转让协议书(范文2篇)
2019/08/15 职场文书
PHP中多字节字符串操作实例详解
2021/08/23 PHP