easyui源码翻译1.32--Tree(树)

前言

使用$.fn.tree.defaults重写默认值对象。下载该插件翻译源码

树控件在web页面中一个将分层数据以树形结构进行显示。它提供用户展开、折叠、拖拽、编辑和异步加载等功能。

源码

 

/**
 * jQuery EasyUI 1.3.2
 * 
 *翻译:qq 1364386878
 */
(function ($) {
    //渲染样式
    function wrapTree(jq) {
        var tree = $(jq);
        tree.addClass("tree");
        return tree;
    };
    // 获取树数据
    function _getTreeData(jq) {
        var data = [];
        collectTreeData(data, $(jq));
        //递归获取节点
        function collectTreeData(nodes, ul) {
            ul.children("li").each(function () {
                var li = $(this);
                var node = $.extend({},
                    $.parser.parseOptions(this, ["id", "iconCls", "state"]),
                    { checked: (li.attr("checked") ? true : undefined) }); 

                node.text = li.children("span").html();
                if (!node.text) {
                    node.text = li.html();
                }
                var uls = li.children("ul");
                if (uls.length) {
                    node.children = [];
                    collectTreeData(node.children, uls);//递归本事
                }
                nodes.push(node);
            });
        };
        return data;
    };
    //事件绑定
    function bindEvent(jq) {
        var options = $.data(jq, "tree").options;
        $(jq).unbind().bind("mouseover", function (e) { //鼠标移上事件
            var tt = $(e.target);
            var nodes = tt.closest("div.tree-node");
            if (!nodes.length) {
                return;
            }
            nodes.addClass("tree-node-hover");
            if (tt.hasClass("tree-hit")) {
                if (tt.hasClass("tree-expanded")) {
                    tt.addClass("tree-expanded-hover");
                } else {
                    tt.addClass("tree-collapsed-hover");
                }
            }
            e.stopPropagation();
        }).bind("mouseout", function (e) {//鼠标离开事件
            var tt = $(e.target);
            var nodes = tt.closest("div.tree-node");
            if (!nodes.length) {
                return;
            }
            nodes.removeClass("tree-node-hover");
            if (tt.hasClass("tree-hit")) {
                if (tt.hasClass("tree-expanded")) {
                    tt.removeClass("tree-expanded-hover");
                } else {
                    tt.removeClass("tree-collapsed-hover");
                }
            }
            e.stopPropagation();
        }).bind("click", function (e) {//单击节点事件
            var tt = $(e.target);
            var nodes = tt.closest("div.tree-node");
            if (!nodes.length) {
                return;
            }
            if (tt.hasClass("tree-hit")) {
                _toggle(jq, nodes[0]);
                return false;
            } else {
                if (tt.hasClass("tree-checkbox")) {
                    _check(jq, nodes[0], !tt.hasClass("tree-checkbox1"));
                    return false;
                } else {
                    select(jq, nodes[0]);
                    options.onClick.call(jq, _getNode(jq, nodes[0]));
                }
            }
            e.stopPropagation();
        }).bind("dblclick", function (e) {//双击结点事件
            var nodes = $(e.target).closest("div.tree-node");
            if (!nodes.length) {
                return;
            }
            select(jq, nodes[0]);
            options.onDblClick.call(jq, _getNode(jq, nodes[0]));
            e.stopPropagation();
        }).bind("contextmenu", function (e) {//右键菜单
            var nodes = $(e.target).closest("div.tree-node");
            if (!nodes.length) {
                return;
            }
            options.onContextMenu.call(jq, e, _getNode(jq, nodes[0]));
            e.stopPropagation();
        });
    };
    //禁用拖放功能
    function _disableDnd(jq) {
        var node = $(jq).find("div.tree-node");
        node.draggable("disable");
        node.css("cursor", "pointer");
    };
    //启用拖放功能
    function _enableDnd(jq) {
        var Tree = $.data(jq, "tree");
        var options = Tree.options;
        var tree = Tree.tree;
        Tree.disabledNodes = [];
        //拖动功能 设置
        tree.find("div.tree-node").draggable({
            disabled: false,
            revert: true,
            cursor: "pointer",
            proxy: function (_1d) {
                var p = $("<div class=\"tree-node-proxy\"></div>").appendTo("body");
                p.html("<span class=\"tree-dnd-icon tree-dnd-no\">&nbsp;</span>" + $(_1d).find(".tree-title").html());
                p.hide();
                return p;
            },
            deltaX: 15,
            deltaY: 15,
            onBeforeDrag: function (e) {
                if (options.onBeforeDrag.call(jq, _getNode(jq, this)) == false) {
                    return false;
                }
                if ($(e.target).hasClass("tree-hit") || $(e.target).hasClass("tree-checkbox")) {
                    return false;
                }
                if (e.which != 1) {
                    return false;
                }
                $(this).next("ul").find("div.tree-node").droppable({ accept: "no-accept" });
                var indent = $(this).find("span.tree-indent");
                if (indent.length) {
                    e.data.offsetWidth -= indent.length * indent.width();
                }
            },
            onStartDrag: function () {
                $(this).draggable("proxy").css({ left: -10000, top: -10000 });
                options.onStartDrag.call(jq, _getNode(jq, this));
                var node = _getNode(jq, this);
                if (node.id == undefined) {
                    node.id = "easyui_tree_node_id_temp";
                    _update(jq, node);
                }
                Tree.draggingNodeId = node.id;
            },
            onDrag: function (e) {
                var x1 = e.pageX, y1 = e.pageY, x2 = e.data.startX, y2 = e.data.startY;
                var d = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
                if (d > 3) {
                    $(this).draggable("proxy").show();
                }
                this.pageY = e.pageY;
            },
            onStopDrag: function () {
                $(this).next("ul").find("div.tree-node").droppable({ accept: "div.tree-node" });
                for (var i = 0; i < Tree.disabledNodes.length; i++) {
                    $(Tree.disabledNodes[i]).droppable("enable");
                }
                Tree.disabledNodes = [];
                var _20 = _find(jq, Tree.draggingNodeId);
                if (_20.id == "easyui_tree_node_id_temp") {
                    _20.id = "";
                    _update(jq, _20);
                }
                options.onStopDrag.call(jq, _20);
            }
        }).droppable({//拉伸插件设置
            accept: "div.tree-node",
            onDragEnter: function (e, source) {
                if (options.onDragEnter.call(jq, this, _getNode(jq, source)) == false) {
                    setdndClass(source, false);
                    $(this).removeClass("tree-node-append tree-node-top tree-node-bottom");
                    $(this).droppable("disable");
                    Tree.disabledNodes.push(this);
                }
            },
            onDragOver: function (e, source) {
                if ($(this).droppable("options").disabled) {
                    return;
                }
                var pageY = source.pageY;
                var top = $(this).offset().top;
                var height = top + $(this).outerHeight();
                setdndClass(source, true);
                $(this).removeClass("tree-node-append tree-node-top tree-node-bottom");
                if (pageY > top + (height - top) / 2) {
                    if (height - pageY < 5) {
                        $(this).addClass("tree-node-bottom");
                    } else {
                        $(this).addClass("tree-node-append");
                    }
                } else {
                    if (pageY - top < 5) {
                        $(this).addClass("tree-node-top");
                    } else {
                        $(this).addClass("tree-node-append");
                    }
                }
                if (options.onDragOver.call(jq, this, _getNode(jq, source)) == false) {
                    setdndClass(source, false);
                    $(this).removeClass("tree-node-append tree-node-top tree-node-bottom");
                    $(this).droppable("disable");
                    Tree.disabledNodes.push(this);
                }
            },
            onDragLeave: function (e, source) {
                setdndClass(source, false);
                $(this).removeClass("tree-node-append tree-node-top tree-node-bottom");
                options.onDragLeave.call(jq, this, _getNode(jq, source));
            },
            onDrop: function (e, source) {
                var target = this;
                var action, point;
                if ($(this).hasClass("tree-node-append")) {
                    action = moveNode;
                } else {
                    action = insertNode;
                    point = $(this).hasClass("tree-node-top") ? "top" : "bottom";
                }
                action(source, target, point);
                $(this).removeClass("tree-node-append tree-node-top tree-node-bottom");
            }
        });

        //设置拖动样式
        function setdndClass(source, dnd) {
            var dndicon = $(source).draggable("proxy").find("span.tree-dnd-icon");
            dndicon.removeClass("tree-dnd-yes tree-dnd-no").addClass(dnd ? "tree-dnd-yes" : "tree-dnd-no");
        };

        function moveNode(nodeEl, parent) {
            if (_getNode(jq, parent).state == "closed") {
                expand(jq, parent, function () {
                    doMoveNode();
                });
            } else {
                doMoveNode();
            }
            function doMoveNode() {
                var nodeData = $(jq).tree("pop", nodeEl);
                $(jq).tree("append", { parent: parent, data: [nodeData] });
                options.onDrop.call(jq, parent, nodeData, "append");
            };
        };
        function insertNode(nodeEl, parent, point) {
            var param = {};
            if (point == "top") {
                param.before = parent;
            } else {
                param.after = parent;
            }
            var nodeData = $(jq).tree("pop", nodeEl);
            param.data = nodeData;
            $(jq).tree("insert", param);
            options.onDrop.call(jq, parent, nodeData, point);
        };
    };
    //将节点设置为勾选或不勾选
    function _check(jq, target, isCheck) {
        var options = $.data(jq, "tree").options;
        if (!options.checkbox) {
            return;
        }
        var node2 = _getNode(jq, target);
        if (options.onBeforeCheck.call(jq, node2, isCheck) == false) {
            return;
        }
        var node = $(target);
        var ck = node.find(".tree-checkbox");
        ck.removeClass("tree-checkbox0 tree-checkbox1 tree-checkbox2");//清空样式
        if (isCheck) {
            ck.addClass("tree-checkbox1");//勾选样式
        } else {
            ck.addClass("tree-checkbox0");//不勾选样式
        }
        //设置级联选中
        if (options.cascadeCheck) {
            setParentsChecked(node);
            setChildrenChecked(node);
        }
        
        options.onCheck.call(jq, node2, isCheck);
        //勾选子结点
        function setChildrenChecked(node) {
            var ck = node.next().find(".tree-checkbox");
            ck.removeClass("tree-checkbox0 tree-checkbox1 tree-checkbox2");
            if (node.find(".tree-checkbox").hasClass("tree-checkbox1")) {
                ck.addClass("tree-checkbox1");//勾选样式(非级联)
            } else {
                ck.addClass("tree-checkbox0");//不勾选样式
            }
        };
        //级联勾选父结点
        function setParentsChecked(node) {
            var parentNode = _getParent(jq, node[0]);
            if (parentNode) {
                var ck = $(parentNode.target).find(".tree-checkbox");
                ck.removeClass("tree-checkbox0 tree-checkbox1 tree-checkbox2");
                if (isAllSelected(node)) {
                    ck.addClass("tree-checkbox1");
                } else {
                    if (isAllNull(node)) {
                        ck.addClass("tree-checkbox0");
                    } else {
                        ck.addClass("tree-checkbox2");
                    }
                }
                setParentsChecked($(parentNode.target));
            }
            //是否全选(非级联勾选)
            function isAllSelected(node) {
              
                var ck = node.find(".tree-checkbox");
                //判断当前勾选框的样式状态
                if (ck.hasClass("tree-checkbox0") || ck.hasClass("tree-checkbox2")) {
                    return false;
                }
                var b = true;
                node.parent().siblings().each(function () {
                    if (!$(this).children("div.tree-node").children(".tree-checkbox").hasClass("tree-checkbox1")) {
                        b = false;
                    }
                });
                return b;
            };
            //是否全未勾选
            function isAllNull(node) {
                var ck = node.find(".tree-checkbox");
                if (ck.hasClass("tree-checkbox1") || ck.hasClass("tree-checkbox2")) {
                    return false;
                }
                var b = true;
                node.parent().siblings().each(function () {
                    if (!$(this).children("div.tree-node").children(".tree-checkbox").hasClass("tree-checkbox0")) {
                        b = false;
                    }
                });
                return b;
            };
        };
    };
    // 设置勾选框的值
    function setCheckBoxValue(jq, target) {
        var options = $.data(jq, "tree").options;
        var node = $(target);
        if (_isLeaf(jq, target)) {//叶子结点
            var ck = node.find(".tree-checkbox");
            if (ck.length) {
                if (ck.hasClass("tree-checkbox1")) {
                    _check(jq, target, true);
                } else {
                    _check(jq, target, false);
                }
            } else {
                if (options.onlyLeafCheck) {////只显示叶子节点前的复选框
                    $("<span class=\"tree-checkbox tree-checkbox0\"></span>").insertBefore(node.find(".tree-title"));
                }
            }
        } else {////非叶子结点
            var ck = node.find(".tree-checkbox");
            if (options.onlyLeafCheck) {
                ck.remove();
            } else {
                if (ck.hasClass("tree-checkbox1")) {
                    _check(jq, target, true);
                } else {
                    if (ck.hasClass("tree-checkbox2")) {
                        var checked = true;
                        var unchecked = true;
                        var children = _getChildren(jq, target);
                        for (var i = 0; i < children.length; i++) {
                            if (children[i].checked) {
                                unchecked = false;
                            } else {
                                checked = false;
                            }
                        }
                        if (checked) {
                            _check(jq, target, true);
                        }
                        if (unchecked) {
                            _check(jq, target, false);
                        }
                    }
                }
            }
        }
    };
    //加载树数据
    function _loadData(jq, ul, data, isAppend) {
        var options = $.data(jq, "tree").options;
        data = options.loadFilter.call(jq, data, $(ul).prev("div.tree-node")[0]);
        if (!isAppend) {
            $(ul).empty();
        }
        var checkedNodes = [];
        var depth = $(ul).prev("div.tree-node").find("span.tree-indent, span.tree-hit").length;
        appendNodes(ul, data, depth);
        if (options.dnd) {
            _enableDnd(jq);
        } else {
            _disableDnd(jq);
        }
        for (var i = 0; i < checkedNodes.length; i++) {
            _check(jq, checkedNodes[i], true);
        }
        setTimeout(function () {
            _61(jq, jq);
        }, 0);
        var node = null;
        if (jq != ul) {
            var _5b = $(ul).prev();
            node = _getNode(jq, _5b[0]);
        }
        options.onLoadSuccess.call(jq, node, data);

        function appendNodes(ul, children, depth) {
            for (var i = 0; i < children.length; i++) {
                var li = $("<li></li>").appendTo(ul);
                var item = children[i];
                if (item.state != "open" && item.state != "closed") {
                    item.state = "open";
                }
                var node = $("<div class=\"tree-node\"></div>").appendTo(li);
                node.attr("node-id", item.id);
                $.data(node[0], "tree-node", { id: item.id, text: item.text, iconCls: item.iconCls, attributes: item.attributes });
                $("<span class=\"tree-title\"></span>").html(item.text).appendTo(node);
                if (options.checkbox) {
                    if (options.onlyLeafCheck) {
                        if (item.state == "open" && (!item.children || !item.children.length)) {
                            if (item.checked) {
                                $("<span class=\"tree-checkbox tree-checkbox1\"></span>").prependTo(node);
                            } else {
                                $("<span class=\"tree-checkbox tree-checkbox0\"></span>").prependTo(node);
                            }
                        }
                    } else {
                        if (item.checked) {
                            $("<span class=\"tree-checkbox tree-checkbox1\"></span>").prependTo(node);
                            checkedNodes.push(node[0]);
                        } else {
                            $("<span class=\"tree-checkbox tree-checkbox0\"></span>").prependTo(node);
                        }
                    }
                }
                if (item.children && item.children.length) {
                    var subul = $("<ul></ul>").appendTo(li);
                    if (item.state == "open") {
                        $("<span class=\"tree-icon tree-folder tree-folder-open\"></span>").addClass(item.iconCls).prependTo(node);
                        $("<span class=\"tree-hit tree-expanded\"></span>").prependTo(node);
                    } else {
                        $("<span class=\"tree-icon tree-folder\"></span>").addClass(item.iconCls).prependTo(node);
                        $("<span class=\"tree-hit tree-collapsed\"></span>").prependTo(node);
                        subul.css("display", "none");
                    }
                    appendNodes(subul, item.children, depth + 1);
                } else {
                    if (item.state == "closed") {
                        $("<span class=\"tree-icon tree-folder\"></span>").addClass(item.iconCls).prependTo(node);
                        $("<span class=\"tree-hit tree-collapsed\"></span>").prependTo(node);
                    } else {
                        $("<span class=\"tree-icon tree-file\"></span>").addClass(item.iconCls).prependTo(node);
                        $("<span class=\"tree-indent\"></span>").prependTo(node);
                    }
                }
                for (var j = 0; j < depth; j++) {
                    $("<span class=\"tree-indent\"></span>").prependTo(node);
                }
            }
        };
    };
    function _61(jq, ul, _63) {
        var options = $.data(jq, "tree").options;
        if (!options.lines) {
            return;
        }
        if (!_63) {
            _63 = true;
            $(jq).find("span.tree-indent").removeClass("tree-line tree-join tree-joinbottom");
            $(jq).find("div.tree-node").removeClass("tree-node-last tree-root-first tree-root-one");
            var _65 = $(jq).tree("getRoots");
            if (_65.length > 1) {
                $(_65[0].target).addClass("tree-root-first");
            } else {
                if (_65.length == 1) {
                    $(_65[0].target).addClass("tree-root-one");
                }
            }
        }
        $(ul).children("li").each(function () {
            var _66 = $(this).children("div.tree-node");
            var ul = _66.next("ul");
            if (ul.length) {
                if ($(this).next().length) {
                    _67(_66);
                }
                _61(jq, ul, _63);
            } else {
                _68(_66);
            }
        });
        var _69 = $(ul).children("li:last").children("div.tree-node").addClass("tree-node-last");
        _69.children("span.tree-join").removeClass("tree-join").addClass("tree-joinbottom");
        function _68(_6a, _6b) {
            var _6c = _6a.find("span.tree-icon");
            _6c.prev("span.tree-indent").addClass("tree-join");
        };
        function _67(_6d) {
            var _6e = _6d.find("span.tree-indent, span.tree-hit").length;
            _6d.next().find("div.tree-node").each(function () {
                $(this).children("span:eq(" + (_6e - 1) + ")").addClass("tree-line");
            });
        };
    };
    function request(_70, ul, _71, _72) {
        var _73 = $.data(_70, "tree").options;
        _71 = _71 || {};
        var _74 = null;
        if (_70 != ul) {
            var _75 = $(ul).prev();
            _74 = _getNode(_70, _75[0]);
        }
        if (_73.onBeforeLoad.call(_70, _74, _71) == false) {
            return;
        }
        var _76 = $(ul).prev().children("span.tree-folder");
        _76.addClass("tree-loading");
        var _77 = _73.loader.call(_70, _71, function (_78) {
            _76.removeClass("tree-loading");
            _loadData(_70, ul, _78);
            if (_72) {
                _72();
            }
        }, function () {
            _76.removeClass("tree-loading");
            _73.onLoadError.apply(_70, arguments);
            if (_72) {
                _72();
            }
        });
        if (_77 == false) {
            _76.removeClass("tree-loading");
        }
    };
    function expand(_7a, _7b, _7c) {
        var _7d = $.data(_7a, "tree").options;
        var hit = $(_7b).children("span.tree-hit");
        if (hit.length == 0) {
            return;
        }
        if (hit.hasClass("tree-expanded")) {
            return;
        }
        var _7e = _getNode(_7a, _7b);
        if (_7d.onBeforeExpand.call(_7a, _7e) == false) {
            return;
        }
        hit.removeClass("tree-collapsed tree-collapsed-hover").addClass("tree-expanded");
        hit.next().addClass("tree-folder-open");
        var ul = $(_7b).next();
        if (ul.length) {
            if (_7d.animate) {
                ul.slideDown("normal", function () {
                    _7d.onExpand.call(_7a, _7e);
                    if (_7c) {
                        _7c();
                    }
                });
            } else {
                ul.css("display", "block");
                _7d.onExpand.call(_7a, _7e);
                if (_7c) {
                    _7c();
                }
            }
        } else {
            var _7f = $("<ul style=\"display:none\"></ul>").insertAfter(_7b);
            request(_7a, _7f[0], { id: _7e.id }, function () {
                if (_7f.is(":empty")) {
                    _7f.remove();
                }
                if (_7d.animate) {
                    _7f.slideDown("normal", function () {
                        _7d.onExpand.call(_7a, _7e);
                        if (_7c) {
                            _7c();
                        }
                    });
                } else {
                    _7f.css("display", "block");
                    _7d.onExpand.call(_7a, _7e);
                    if (_7c) {
                        _7c();
                    }
                }
            });
        }
    };
    function _collapse(_81, _82) {
        var _83 = $.data(_81, "tree").options;
        var hit = $(_82).children("span.tree-hit");
        if (hit.length == 0) {
            return;
        }
        if (hit.hasClass("tree-collapsed")) {
            return;
        }
        var _84 = _getNode(_81, _82);
        if (_83.onBeforeCollapse.call(_81, _84) == false) {
            return;
        }
        hit.removeClass("tree-expanded tree-expanded-hover").addClass("tree-collapsed");
        hit.next().removeClass("tree-folder-open");
        var ul = $(_82).next();
        if (_83.animate) {
            ul.slideUp("normal", function () {
                _83.onCollapse.call(_81, _84);
            });
        } else {
            ul.css("display", "none");
            _83.onCollapse.call(_81, _84);
        }
    };
    function _toggle(_86, _87) {
        var hit = $(_87).children("span.tree-hit");
        if (hit.length == 0) {
            return;
        }
        if (hit.hasClass("tree-expanded")) {
            _collapse(_86, _87);
        } else {
            expand(_86, _87);
        }
    };
    function _expandAll(_89, _8a) {
        var _8b = _getChildren(_89, _8a);
        if (_8a) {
            _8b.unshift(_getNode(_89, _8a));
        }
        for (var i = 0; i < _8b.length; i++) {
            expand(_89, _8b[i].target);
        }
    };
    function _expandTo(_8d, _8e) {
        var _8f = [];
        var p = _getParent(_8d, _8e);
        while (p) {
            _8f.unshift(p);
            p = _getParent(_8d, p.target);
        }
        for (var i = 0; i < _8f.length; i++) {
            expand(_8d, _8f[i].target);
        }
    };
    function _collapseAll(_92, _93) {
        var _94 = _getChildren(_92, _93);
        if (_93) {
            _94.unshift(_getNode(_92, _93));
        }
        for (var i = 0; i < _94.length; i++) {
            _collapse(_92, _94[i].target);
        }
    };
    // 获取根结点
    function _getRoot(jq) {
        var rootNodes = _getRoots(jq);
        if (rootNodes.length) {
            return rootNodes[0];
        } else {
            return null;
        }
    };
    // 获取所有根结点
    function _getRoots(jq) {
        var roots = [];
        $(jq).children("li").each(function () {
            var nodes = $(this).children("div.tree-node");
            roots.push(_getNode(jq, nodes[0]));
        });
        return roots;
    };
    //获取所有子结点
    function _getChildren(jq, target) {
        var ndoes = [];
        if (target) {
            findChildren($(target));
        } else {
            var rootNodes = _getRoots(jq);
            for (var i = 0; i < rootNodes.length; i++) {
                ndoes.push(rootNodes[i]);
                findChildren($(rootNodes[i].target));
            }
        }
        function findChildren(target) {
            target.next().find("div.tree-node").each(function () {
                ndoes.push(_getNode(jq, this));
            });
        };
        return ndoes;
    };
    //获取父结点
    function _getParent(jq, target) {
        var ul = $(target).parent().parent();
        if (ul[0] == jq) {
            return null;
        } else {
            return _getNode(jq, ul.prev()[0]);
        }
    };
    //获取所有被勾选的结点
    function _getChecked(jq, state) {
        state = state || "checked";
        var stateClass = "";
        if (state == "checked") {
            stateClass = "span.tree-checkbox1";
        } else {
            if (state == "unchecked") {
                stateClass = "span.tree-checkbox0";
            } else {
                if (state == "indeterminate") {
                    stateClass = "span.tree-checkbox2";
                }
            }
        }
        var node = [];
        $(jq).find(stateClass).each(function () {
            var _a9 = $(this).parent();
            node.push(_getNode(jq, _a9[0]));
        });
        return node;
    };
    //获取被选中的结点
    function _getSelected(jq) {
        var nodes = $(jq).find("div.tree-node-selected");
        if (nodes.length) {
            return _getNode(jq, nodes[0]);
        } else {
            return null;
        }
    };
    //追加若干子节点到一个父节点
    function _append(jq, param) {
        var parent = $(param.parent);
        var ul;
        if (parent.length == 0) {
            ul = $(jq);
        } else {
            ul = parent.next();
            if (ul.length == 0) {
                ul = $("<ul></ul>").insertAfter(parent);
            }
        }
        if (param.data && param.data.length) {
            var icon = parent.find("span.tree-icon");
            if (icon.hasClass("tree-file")) {
                icon.removeClass("tree-file").addClass("tree-folder tree-folder-open");
                var hit = $("<span class=\"tree-hit tree-expanded\"></span>").insertBefore(icon);
                if (hit.prev().length) {
                    hit.prev().remove();
                }
            }
        }
        _loadData(jq, ul[0], param.data, true);
        setCheckBoxValue(jq, ul.prev());
    };
    //在一个指定节点之前或之后插入节点
    function _insert(jq, target) {
        var ref = target.before || target.after;
        var parentNode = _getParent(jq, ref);
        var li;
        if (parentNode) {
            _append(jq, { parent: parentNode.target, data: [target.data] });
            li = $(parentNode.target).next().children("li:last");
        } else {
            _append(jq, { parent: null, data: [target.data] });
            li = $(jq).children("li:last");
        }
        if (target.before) {
            li.insertBefore($(ref).parent());
        } else {
            li.insertAfter($(ref).parent());
        }
    };
    //删除一个节点和它的子节点
    function _remove(jq, target) {
        var parentNode = _getParent(jq, target);
        var node = $(target);
        var li = node.parent();
        var ul = li.parent();
        li.remove();
        if (ul.children("li").length == 0) {
            var node = ul.prev();
            node.find(".tree-icon").removeClass("tree-folder").addClass("tree-file");
            node.find(".tree-hit").remove();
            $("<span class=\"tree-indent\"></span>").prependTo(node);
            if (ul[0] != jq) {
                ul.remove();
            }
        }
        if (parentNode) {
            setCheckBoxValue(jq, parentNode.target);
        }
        _61(jq, jq);
    };
    //递归获取某结点数据(包括子结点)  
    function _getData(jq, target) {
        // 获取下一结点的子结点
        function getChildrenOfNextNode(node, ul) {
            ul.children("li").each(function () {
                var nodes = $(this).children("div.tree-node");
                var node = _getNode(jq, nodes[0]);
                var sub = $(this).children("ul");
                if (sub.length) {
                    node.children = [];
                    getChildrenOfNextNode(node.children, sub);
                }
                node.push(node);
            });
        };
        if (target) {
            var node = _getNode(jq, target);
            node.children = [];
            getChildrenOfNextNode(node.children, $(target).next());
            return node;
        } else {
            return null;
        }
    };
    //更新指定的节点
    function _update(jq, param) {
        var target = $(param.target);
        var node = _getNode(jq, param.target);
        if (node.iconCls) {
            target.find(".tree-icon").removeClass(node.iconCls);
        }
        var options = $.extend({}, node, param);
        $.data(param.target, "tree-node", options);
        target.attr("node-id", options.id);
        target.find(".tree-title").html(options.text);
        if (options.iconCls) {
            target.find(".tree-icon").addClass(options.iconCls);
        }
        if (node.checked != options.checked) {
            _check(jq, param.target, options.checked);
        }
    };
    //获取结点
    function _getNode(jq, target) {
        var node = $.extend({}, $.data(target, "tree-node"), { target: target, checked: $(target).find(".tree-checkbox").hasClass("tree-checkbox1") });
        if (!_isLeaf(jq, target)) {
            node.state = $(target).find(".tree-hit").hasClass("tree-expanded") ? "open" : "closed";
        }
        return node;
    };
    //根据ID查找结点
    function _find(jq, id) {
        //
        var nodes = $(jq).find("div.tree-node[node-id=" + id + "]");
        if (nodes.length) {
            return _getNode(jq, nodes[0]);
        } else {
            return null;
        }
    };
    // 选择结点
    function select(jq, target) {
        var options = $.data(jq, "tree").options;
        var node = _getNode(jq, target);
        if (options.onBeforeSelect.call(jq, node) == false) {
            return;
        }
        $("div.tree-node-selected", jq).removeClass("tree-node-selected");
        $(target).addClass("tree-node-selected");
        options.onSelect.call(jq, node);
    };
    //是否叶子结点
    function _isLeaf(jq, target) {
        var node = $(target);
        var hit = node.children("span.tree-hit");
        return hit.length == 0;
    };
    //开始编辑结点
    function _beginEdit(jq, target) {
        var options = $.data(jq, "tree").options;
        var node = _getNode(jq, target);
        if (options.onBeforeEdit.call(jq, node) == false) {
            return;
        }
        $(target).css("position", "relative");
        var nt = $(target).find(".tree-title");
        var outerWidth = nt.outerWidth();
        nt.empty();
        var editor = $("<input class=\"tree-editor\">").appendTo(nt);//编辑器
        editor.val(node.text).focus();
        editor.width(outerWidth + 20);
        editor.height(document.compatMode == "CSS1Compat" ? (18 - (editor.outerHeight() - editor.height())) : 18);
        //设置编辑器事件
        editor.bind("click", function (e) {
            return false;
        }).bind("mousedown", function (e) {
            e.stopPropagation();
        }).bind("mousemove", function (e) {
            e.stopPropagation();
        }).bind("keydown", function (e) {
            if (e.keyCode == 13) {
                _endEdit(jq, target);
                return false;
            } else {
                if (e.keyCode == 27) {
                    _cancelEdit(jq, target);
                    return false;
                }
            }
        }).bind("blur", function (e) {
            e.stopPropagation();
            _endEdit(jq, target);
        });
    };
    //结束编辑
    function _endEdit(jq, target) {
        var options = $.data(jq, "tree").options;
        $(target).css("position", "");
        var editor = $(target).find("input.tree-editor");
        var val = editor.val();
        editor.remove();
        var node = _getNode(jq, target);
        node.text = val;
        _update(jq, node);
        options.onAfterEdit.call(jq, node);
    };
    // 取消编辑
    function _cancelEdit(jq, target) {
        var options = $.data(jq, "tree").options;
        $(target).css("position", "");
        $(target).find("input.tree-editor").remove();
        var node = _getNode(jq, target);
        _update(jq, node);
        options.onCancelEdit.call(jq, node);
    };
    //实例化树
    $.fn.tree = function (options, param) {
        if (typeof options == "string") {
            return $.fn.tree.methods[options](this, param);
        }
        var options = options || {};

        return this.each(function () {
            var data = $.data(this, "tree");
            var options;
            if (data) {
                options = $.extend(data.options, options);
                data.options = options;
            } else {
                options = $.extend({}, $.fn.tree.defaults, $.fn.tree.parseOptions(this), options);
                $.data(this, "tree", { options: options, tree: wrapTree(this) });

                var jsonData = _getTreeData(this);
                if (jsonData.length && !options.data) {
                    options.data = jsonData;
                }
            }
            bindEvent(this);
            if (options.lines) {
                $(this).addClass("tree-lines");
            }
            if (options.data) {
                _loadData(this, this, options.data);
            } else {
                if (options.dnd) {
                    _enableDnd(this);
                } else {
                    _disableDnd(this);
                }
            }
            request(this, this);
        });
    };
    //树 方法
    $.fn.tree.methods = {
        //返回树控件属性
        options: function (jq) {
            return $.data(jq[0], "tree").options;
        },
        //读取树控件数据
        loadData: function (jq, data) {
            return jq.each(function () {
                _loadData(this, this, data);
            });
        },
        //获取指定节点对象 
        getNode: function (jq, target) {
            return _getNode(jq[0], target);
        },
        //获取指定节点数据,包含它的子节点
        getData: function (jq, target) {
            return _getData(jq[0], target);
        },
        //重新载入树控件数据
        reload: function (jq, target) {
            return jq.each(function () {
                if (target) {
                    var node = $(target);
                    var hit = node.children("span.tree-hit");//获取结点前的展开/折叠对象
                    hit.removeClass("tree-expanded tree-expanded-hover").addClass("tree-collapsed");
                    node.next().remove();//删除子结点
                    expand(this, target);//调用展开方法,重新加载树
                } else {
                    $(this).empty();
                    request(this, this);
                }
            });
        },
        //获取根节点,返回节点对象
        getRoot: function (jq) {
            return _getRoot(jq[0]);
        },
        //获取所有根节点,返回节点数组
        getRoots: function (jq) {
            return _getRoots(jq[0]);
        },
        //获取父节点,'target'参数代表节点的DOM对象
        getParent: function (jq, target) {
            return _getParent(jq[0], target);
        },
        //获取所有子节点,'target'参数代表节点的DOM对象
        getChildren: function (jq, target) {
            return _getChildren(jq[0], target);
        },
        //获取所有选中的节点。'state'可用值有:'checked','unchecked','indeterminate'。如果'state'未指定,将返回'checked'节点
        getChecked: function (jq, state) {
            return _getChecked(jq[0], state);
        },
        //获取选择节点并返回它,如果未选择则返回null
        getSelected: function (jq) {
            return _getSelected(jq[0]);
        },
        //判断指定的节点是否是叶子节点,target参数是一个节点DOM对象
        isLeaf: function (jq, target) {
            return _isLeaf(jq[0], target);
        },
        //查找指定节点并返回节点对象
        find: function (jq, id) {
            return _find(jq[0], id);
        },
        //选择一个节点,'target'参数表示节点的DOM对象
        select: function (jq, target) {
            return jq.each(function () {
                select(this, target);
            });
        },
        //选中指定节点
        check: function (jq, target) {
            return jq.each(function () {
                _check(this, target, true);
            });
        },
        //取消选中指定节点
        uncheck: function (jq, target) {
            return jq.each(function () {
                _check(this, target, false);
            });
        },
        //折叠一个节点,'target'参数表示节点的DOM对象
        collapse: function (jq, target) {
            return jq.each(function () {
                _collapse(this, target);
            });
        },
        //展开一个节点,'target'参数表示节点的DOM对象。在节点关闭或没有子节点的时候,节点ID的值(名为'id'的参数)将会发送给服务器  请求子节点的数据。 
        expand: function (jq, target) {
            return jq.each(function () {
                expand(this, target);
            });
        },
        //折叠所有节点
        collapseAll: function (jq, target) {
            return jq.each(function () {
                _collapseAll(this, target);
            });
        },
        //展开所有节点
        expandAll: function (jq, target) {
            return jq.each(function () {
                _expandAll(this, target);
            });
        },
        //打开从根节点到指定节点之间的所有节点
        expandTo: function (jq, target) {
            return jq.each(function () {
                _expandTo(this, target);
            });
        },
        //打开或关闭节点的触发器,target参数是一个节点DOM对象
        toggle: function (jq, target) {
            return jq.each(function () {
                _toggle(this, target);
            });
        },
        //追加若干子节点到一个父节点,param参数有2个属性
        append: function (jq, param) {
            return jq.each(function () {
                _append(this, param);
            });
        },
        //在一个指定节点之前或之后插入节点,'param'参数包含如下属性:
        //before:DOM对象,在某个节点之前插入。
        //after:DOM对象,在某个节点之后插入。
        //data:对象,节点数据
        insert: function (jq, param) {
            return jq.each(function () {
                _insert(this, param);
            });
        },
        //移除一个节点和它的子节点,'target'参数是该节点的DOM对象
        remove: function (jq, target) {
            return jq.each(function () {
                _remove(this, target);
            });
        },
        //移除一个节点和它的子节点,该方法跟remove方法一样,不同的是它将返回被移除的节点数据
        pop: function (jq, target) {
            var node = jq.tree("getData", target);
            jq.tree("remove", target);
            return node;
        },
        //更新指定节点。'param'参数包含以下属性:
        //target(DOM对象,将被更新的目标节点),id,text,iconCls,checked等
        update: function (jq, target) {
            return jq.each(function () {
                _update(this, target);
            });
        },
        //启用拖拽功能
        enableDnd: function (jq) {
            return jq.each(function () {
                _enableDnd(this);
            });
        },
        //禁用拖拽功能
        disableDnd: function (jq) {
            return jq.each(function () {
                _disableDnd(this);
            });
        },
        //开始编辑一个节点
        beginEdit: function (jq, target) {
            return jq.each(function () {
                _beginEdit(this, target);
            });
        },
        //结束编辑一个节点
        endEdit: function (jq, target) {
            return jq.each(function () {
                _endEdit(this, target);
            });
        },
        //取消编辑一个节点
        cancelEdit: function (jq, target) {
            return jq.each(function () {
                _cancelEdit(this, target);
            });
        }
    };
    //解析器
    $.fn.tree.parseOptions = function (target) {
        var t = $(target);
        return $.extend({},
            $.parser.parseOptions(target, ["url", "method", { checkbox: "boolean", cascadeCheck: "boolean", onlyLeafCheck: "boolean" },
                { animate: "boolean", lines: "boolean", dnd: "boolean" }]));
    };
    //树-默认属性+事件
    $.fn.tree.defaults = {
        url: null,//检索远程数据的URL地址
        method: "post",//检索数据的HTTP方法。(POST / GET)
        animate: false,//定义节点在展开或折叠的时候是否显示动画效果
        checkbox: false,//定义是否在每一个借点之前都显示复选框
        cascadeCheck: true,//定义是否层叠选中状态
        onlyLeafCheck: false,//定义是否只在末级节点之前显示复选框
        lines: false,//定义是否显示树控件上的虚线
        dnd: false,//定义是否启用拖拽功能
        data: null,//节点数据加载
        //定义如何从远程服务器加载数据。返回false可以忽略本操作
        loader: function (param, _success, _error) {
            var opts = $(this).tree("options");
            if (!opts.url) {
                return false;
            }
            $.ajax({
                type: opts.method,
                url: opts.url,
                data: param,
                dataType: "json",
                success: function (data) {
                    _success(data);
                },
                error: function () {
                    _error.apply(this, arguments);
                }
            });
        },
        //返回过滤过的数据进行展示。返回数据是标准树格式
        loadFilter: function (data, parent) {
            return data;
        },
        //事件--
        //在请求加载远程数据之前触发,返回false可以取消加载操作
        onBeforeLoad: function (node, param) {
        },
        //在数据加载成功以后触发
        onLoadSuccess: function (node, data) {
        },
        //在数据加载失败的时候触发,arguments参数和jQuery的$.ajax()函数里面的'error'回调函数的参数相同
        onLoadError: function () {
        },
        //在用户点击一个节点的时候触发
        onClick: function (node) {
        },
        //在用户双击一个节点的时候触发
        onDblClick: function (node) {
        },
        //在节点展开之前触发,返回false可以取消展开操作
        onBeforeExpand: function (node) {
        },
        //在节点展开的时候触发
        onExpand: function (node) {
        },
        //在节点折叠之前触发,返回false可以取消折叠操作
        onBeforeCollapse: function (node) {
        },
        //在节点折叠的时候触发
        onCollapse: function (node) {
        },
        //在用户点击勾选复选框之前触发,返回false可以取消选择动作
        onBeforeCheck: function (node, checked) {
        },
        //在用户点击勾选复选框的时候触发
        onCheck: function (node, checked) {
        },
        //在用户选择一个节点之前触发,返回false可以取消选择动作
        onBeforeSelect: function (node) {
        },
        //在用户选择节点的时候触发
        onSelect: function (node) {
        },
        //在右键点击节点的时候触发
        onContextMenu: function (e, node) {
        },
        //在开始拖动节点之前触发,返回false可以拒绝拖动
        onBeforeDrag: function (node) {
        },
        //在开始拖动节点的时候触发
        onStartDrag: function (node) {
        },
        //在停止拖动节点的时候触发
        onStopDrag: function (node) {
        },
        //在拖动一个节点进入到某个目标节点并释放的时候触发,返回false可以拒绝拖动
        onDragEnter: function (target, source) {
        },
        //在拖动一个节点经过某个目标节点并释放的时候触发,返回false可以拒绝拖动
        onDragOver: function (target, source) {
        },
        //在拖动一个节点离开某个目标节点并释放的时候触发,返回false可以拒绝拖动
        onDragLeave: function (target, source) {
        },
        //当节点位置被拖动时触发
        onDrop: function (target, source, point) {
        },
        //在编辑节点之前触发
        onBeforeEdit: function (node) {
        },
        //在编辑节点之后触发
        onAfterEdit: function (node) {
        },
        //在取消编辑操作的时候触发
        onCancelEdit: function (node) {
        }
    };
})(jQuery);
View Code

 

示例代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Basic Tree - jQuery EasyUI Demo</title>
    <link rel="stylesheet" type="text/css" href="../../themes/default/easyui.css">
    <link rel="stylesheet" type="text/css" href="../../themes/icon.css">
    <link rel="stylesheet" type="text/css" href="../demo.css">
    <script type="text/javascript" src="../../jquery-1.8.0.min.js"></script>
    <script src="../../plugins2/jquery.parser.js"></script>
    <script src="../../plugins2/jquery.draggable.js"></script>
    <script src="../../plugins2/jquery.droppable.js"></script>
    <script src="../../plugins2/jquery.tree.js"></script>
</head>
<body>
    <h2>Basic Tree</h2>
    <div class="demo-info">
        <div class="demo-tip icon-tip"></div>
        <div>Click the arrow on the left to expand or collapse nodes.</div>
    </div>
    <div style="margin:10px 0;"></div>
    <ul class="easyui-tree">
        <li>
            <span>My Documents</span>
            <ul>
                <li data-options="state:'closed'">
                    <span>Photos</span>
                    <ul>
                        <li>
                            <span>Friend</span>
                        </li>
                        <li>
                            <span>Wife</span>
                        </li>
                        <li>
                            <span>Company</span>
                        </li>
                    </ul>
                </li>
                <li>
                    <span>Program Files</span>
                    <ul>
                        <li>Intel</li>
                        <li>Java</li>
                        <li>Microsoft Office</li>
                        <li>Games</li>
                    </ul>
                </li>
                <li>index.html</li>
                <li>about.html</li>
                <li>welcome.html</li>
            </ul>
        </li>
    </ul>

</body>
</html>
View Code

 

插件效果

posted @ 2014-01-01 23:03  Jimmy-Lee  阅读(850)  评论(1编辑  收藏  举报