邀请Ext爱好者一起解决授权树模型的问题

碰到一个问题解决不了,请大家帮分析一下!
问题是这样的,我要一个用来授权时候用的授权树,她的基本需求如下:
1.可以复选节点。
2.选中节点后要递归选中其所有子节点;取消选中状态后,要递归取消其所有子节点。
3.选中节点后腰递归选中所有直系父节点,如果某节点的所有子节点都被取消了则取消所有直系父节点的选中状态。

我目前已经实现了大部分功能(参考了E3项目授权树模型代码),但有一个Bug,选中某一叶子节点,则所有节点会被选中。

            /**
             * 监听节点的选中状态
             /
            tree.on('checkchange', function(pNode, pChecked) {
                        pNode.attributes.checked = pChecked;
                        /
*
                         * 说明:
                         * 下面这两个方法同时调用就回出现,选择一个叶子节点则所有节点都被选中的Bug
                         * 如果只是调用其中任一个方法,则选中子节点功能和选中父节点功能都是正常的
                         * 小弟水平有限,实在找不出问题所在,特请大家看看
                         /
                        checkChildren(pNode);
                        checkParents(pNode);

                    });

附件里面已经打包了Ext3.1的SDK,下载解压后便可以直接修改代码调试。有兴趣的可以看看!多谢!



部分代码如下:


/
*

  • 树模型测试
    */
    Ext.onReady(function() {
    Ext.QuickTips.init();
    Ext.form.Field.prototype.msgTarget = 'qtip';
    Ext.BLANK_IMAGE_URL = './resource/image/ext/s.gif';
    var node00 = new Ext.tree.TreeNode({
    text : '根节点00',
    expanded : true,
    checked : false,
    // leaf:false,
    id : '00'
    });
    var node0001 = new Ext.tree.TreeNode({
    text : '节点0001',
    expanded : true,
    checked : false,
    // leaf:false,
    id : '0001'
    });
    var node000101 = new Ext.tree.TreeNode({
    text : '节点000101',
    expanded : true,
    checked : false,
    // leaf:false,
    id : '000101'
    });
    var node000102 = new Ext.tree.TreeNode({
    text : '节点000102',
    expanded : true,
    checked : false,
    // leaf:true,
    id : '000102'
    });
    var node00010103 = new Ext.tree.TreeNode({
    text : '节点00010103',
    expanded : true,
    checked : false,
    // leaf:true,
    id : 'node00010103'
    });
    node00.appendChild(node0001);
    node0001.appendChild(node000101);
    node0001.appendChild(node000102);
    node000101.appendChild(node00010103);
    var tree = new Ext.tree.TreePanel({
    autoHeight : false,
    autoWidth : false,
    autoScroll : true,
    animate : false,
    rootVisible : true,
    title : '测试',
    border : false,
    containerScroll : true,
    applyTo : 'treeDiv',
    root : node00
    });
    node00.expand();
    var checkChildren = function(node) {
    if (node.isLeaf()) {// 非叶子节点
    return;
    }
    //alert('1');
    var nodeUI = node.getUI();
    var children = node.childNodes;
    //alert(children.length);
    for (var i = 0; i < children.length; i++) {
    var child = children[i];
    var childUI = child.getUI();
    if (typeof child.attributes.checked == 'undefined') continue;
    if (child.attributes.checked == node.attributes.checked) continue;
    childUI.toggleCheck(nodeUI.isChecked());
    child.attributes.checked = nodeUI.isChecked();
    checkChildren(child);
    }
    };

        /**
         * 递归选中父节点
         */
        var checkParents = function(node) {
            if (node == null) {
                return;
            }
            var nodeUI = node.getUI();
            if (typeof node.attributes.checked == 'undefined') {
                return;
            }
            if (node.attributes.checked == false) {// 取消父亲.
                uncheckParents(node);
                return;
            }
            var parentNode = node.parentNode;
            if (parentNode == null) {
                return;
            }
            var parentNodeUI = parentNode.getUI();
            if (typeof parentNode.attributes.checked == 'undefined') {
                return;
            }
            if (parentNode.attributes.checked) {// 已经选种
                return;
            }
            parentNodeUI.toggleCheck(true);
            parentNode.getOwnerTree().fireEvent('onChecked', parentNode);
            parentNode.attributes.checked = true;
            checkParents(parentNode);
        };
    
        /**
         * 递归取消父节点选中状态
         */
        var uncheckParents = function(node) {
            var parentNode = node.parentNode;
            if (parentNode == null) {
                return;
            }
            var parentNodeUI = parentNode.getUI();
            if (typeof parentNode.attributes.checked == 'undefined') {
                return;
            }
    
            var children = parentNode.childNodes;
            for (var i = 0; i &lt; children.length; i++) {
                var child = children[i];
                var childUI = child.getUI();
                if (typeof child.attributes.checked == 'undefined') {
                    continue;
                }
                if (child.attributes.checked == true) {
                    return;
                }
            }
            parentNodeUI.toggleCheck(false);
            parentNode.attributes.checked = false;
            parentNode.getOwnerTree().fireEvent('onUnchecked', parentNode);
            uncheckParents(parentNode);
        };
    
        /**
         * 监听节点的选中状态
         */
        tree.on('checkchange', function(pNode, pChecked) {
                    pNode.attributes.checked = pChecked;
                    /**
                     * 说明:
                     * 下面这两个方法同时调用就回出现,选择一个叶子节点则所有节点都被选中的Bug
                     * 如果只是调用其中任一个方法,则选中子节点功能和选中父节点功能都是正常的
                     * 小弟水平有限,实在找不出问题所在
                     */
                    checkChildren(pNode);
                    checkParents(pNode);
    
                });
    
    })
    

[code="js"]
function cascadeParent(){
var pn = this.parentNode;
if (!pn || !Ext.isBoolean(this.attributes.checked))
return;
if (this.attributes.checked) {//级联选中
pn.getUI().toggleCheck(true);
}
else {//级联未选中
var b = true;
Ext.each(pn.childNodes, function(n){
if (n.getUI().isChecked()){
return b = false;
}
return true;
});
if (b)
pn.getUI().toggleCheck(false);
}
pn.cascadeParent();
}

function cascadeChildren(){
    var ch = this.attributes.checked;
    if (!Ext.isBoolean(ch)) 
        return;
    Ext.each(this.childNodes, function(n){

        n.getUI().toggleCheck(ch);
        n.cascadeChildren();
    });
}
/**
 * 为TreeNode对象添加级联父节点和子节点的方法
 */
Ext.apply(Ext.tree.TreeNode.prototype, {
    cascadeParent: cascadeParent,
    cascadeChildren: cascadeChildren
});
/**
 * Checkbox被点击后级联父节点和子节点
 */
Ext.override(Ext.tree.TreeEventModel, {
    onCheckboxClick: Ext.tree.TreeEventModel.prototype.onCheckboxClick.createSequence(function(e, node){
        node.cascadeParent();
        node.cascadeChildren();
    })
});

[/code]
把这段代码加到Ext.onReady(function() { 下面就可以实现级联了,其实就是为TreeNode添加两个级联函数,修改TreeEventModel的onCheckboxClick函数使得用户点击checkbox后进行级联,好处就是如果你是通过代码对选中状态进行设置级联方法是不会执行的

treepanel里面有checkModel这么个属性,用于控制级联选中模式

http://chemzqm.iteye.com/blog/632970 可以参照这位哥们的代码 然后略加修改就行了

没时间看代码,马上下班了,我感觉是你单击了叶节点然后触发了其直系节点的点击事件,从而由于你点节点级联选中所有子节点,所以就选中了所有选中节点同级的节点。这里要处理这个事件,传个不同的参数,或者可以有一种半选状态,也就是三态的