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 相关文章推荐
页面js遇到乱码问题的解决方法是和无法转码的情况
Apr 30 Javascript
javascript中sort() 方法使用详解
Aug 30 Javascript
chrome浏览器当表单自动填充时如何去除浏览器自动添加的默认样式
Oct 09 Javascript
用JavaScript来美化HTML的select标签的下拉列表效果
Nov 17 Javascript
jQuery取得iframe中元素的常用方法详解
Jan 14 Javascript
ECharts仪表盘实例代码(附源码下载)
Feb 18 Javascript
javascript动态获取登录时间和在线时长
Feb 25 Javascript
jquery中用函数来设置css样式
Dec 22 Javascript
详解vuex中mapState,mapGetters,mapMutations,mapActions的作用
Apr 13 Javascript
微信小程序实现tab页面切换功能
Jul 13 Javascript
微信小程序表单验证form提交错误提示效果
Jun 19 Javascript
JavaScript 高性能数组去重的方法
Sep 20 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
用PHP实现WEB动态网页静态
2006/10/09 PHP
PHP中文件读、写、删的操作(PHP中对文件和目录操作)
2012/03/06 PHP
163的邮件用phpmailer发送(实例详解)
2013/06/24 PHP
一个简单安全的PHP验证码类 附调用方法
2016/06/24 PHP
Mootools 1.2教程 选项卡效果(Tabs)
2009/09/15 Javascript
jquery last-child 列表最后一项的样式
2010/01/22 Javascript
利用google提供的API(JavaScript接口)获取网站访问者IP地理位置的代码详解
2010/07/24 Javascript
如何将一个String和多个String值进行比较思路分析
2013/04/22 Javascript
JavaScript 实现鼠标拖动元素实例代码
2014/02/24 Javascript
Jsonp post 跨域方案
2015/07/06 Javascript
自己动手写的javascript前端等待控件
2015/10/30 Javascript
原生JS实现风箱式demo,并封装了一个运动框架(实例代码)
2016/07/22 Javascript
只需五句话搞定JavaScript作用域(经典)
2016/07/26 Javascript
JS之相等操作符详解
2016/09/13 Javascript
JavaScript Canvas绘制圆形时钟效果
2020/08/20 Javascript
H5上传本地图片并预览功能
2017/05/08 Javascript
Django与Vue语法的冲突问题完美解决方法
2017/12/14 Javascript
NodeJS如何实现同步的方法示例
2018/08/24 NodeJs
layui layer select 选择被遮挡的解决方法
2019/09/21 Javascript
微信小程序如何实现在线客服功能
2019/10/16 Javascript
vue学习笔记之slot插槽基本用法实例分析
2020/02/01 Javascript
python简单的函数定义和用法实例
2015/05/07 Python
讲解Python的Scrapy爬虫框架使用代理进行采集的方法
2016/02/18 Python
使用Python读写文本文件及编写简单的文本编辑器
2016/03/11 Python
Python中struct模块对字节流/二进制流的操作教程
2017/01/21 Python
Python获取CPU、内存使用率以及网络使用状态代码
2018/02/08 Python
Python实现的统计文章单词次数功能示例
2019/07/08 Python
python函数的万能参数传参详解
2019/07/26 Python
Django实现将views.py中的数据传递到前端html页面,并展示
2020/03/16 Python
VS2019+python3.7+opencv4.1+tensorflow1.13配置详解
2020/04/16 Python
利用CSS3的transform做的动态时钟效果
2011/09/21 HTML / CSS
Timberland澳大利亚官网:全球领先的户外品牌
2019/12/10 全球购物
理货员的岗位职责
2013/11/23 职场文书
珍珠鸟教学反思
2014/02/01 职场文书
青岛导游词
2015/02/12 职场文书
vue里使用create, mounted调用方法
2022/04/26 Vue.js