欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JS--插件: 树Tree 开发与实现

程序员文章站 2022-05-29 10:27:48
日常在Web项目开发时,经常会碰到树形架构数据的显示,从数据库中获取数据,并且显示成树形。为了方便,我们可以写一个javascript的一个跨浏览器树控件,后续可以重复使用。本节分享一个自己开发的JS tree插件,对有需要的朋友可以直接下载使用。 Tree插件 需要实现 (1)、自动将数据组织成上 ......

   日常在web项目开发时,经常会碰到树形架构数据的显示,从数据库中获取数据,并且显示成树形。为了方便,我们可以写一个javascript的一个跨浏览器树控件,后续可以重复使用。本节分享一个自己开发的js tree插件,对有需要的朋友可以直接下载使用。

   tree插件 需要实现

       (1)、自动将数据组织成上下级关系,这样我们在前端手工添加数据或者从数据库中获取到的数据不需要我们来组织上下级关系

       (2)、支持自定 加载目录树  支持xml、json 格式的数据加载

       (3)、实现树节点的选择(单选、复选[级联选择])功能

       (4)、支持大数据的一次性加载

       。。。。。。

   下面开始分享自己写的一个tree 插件:  此插件基于jquery  需要引用

   

    第一:插件中每个树节点node的参数json对象如下所示

            nodeitem: function () {
                return {
                    nodecode: "",             //  节点编码
                    nodetext: "",               //  节点文本 [节点显示文本]
                    nodetitle: "",               //  节点标题 [用于鼠标移过时显示的节点文本]
                    supnodecode: "",       //  上级节点编码 [定义此节点所属的上级节点编码,通过此编码来组成上下级关系]
                    nodeurl: "",                 //  节点url 表示当前节点自定的链接url地址
                    iconexpand: "",           //  节点展开图标 [目录树节点自定展开状态下显示的图标,如果为空,则采用默认的图标]
                    iconcollapse: ""          //  节点收缩图标 [目录树节点自定收缩状态下显示的图标,如果为空,则采用默认的图标]
                }
            }

     第二:加载目录树的三种方法

             1、loadjson(json)             json 对象目录树节点数组(一次性完成)

                                                       json 格式 是一个array 数组  每项为一个 nodeitem 对象的参数
                                                       [

                                                            {   nodecode: "", nodetext: "", nodetitle: "",supnodecode: "",nodeurl: "",iconexpand: "" ,iconcollapse: "" },
                                                            {},...
                                                       ]


             2、loadxml(xml)                 xml字符串格式的节点数据(一次性完成)

                                                        说明:采用xml字符串格式  注意节点 tagname:nodecode nodetext 等 不允许变更 因为程序内部是直接采用这个名字来获取的        
                                                       <root>
                                                             <item>   //  每一个节点 内包含多个数据值   
                                                                  <nodecode><![cdata[节点编码值]]></nodecode>    
                                                                  <nodetext><![cdata[节点名称文本 ]]></nodetext>
                                                                  <nodetitle><![cdata[节点鼠标移入显示提示文本]]></nodetitle>
                                                                  <supnodecode><![cdata[节点所属上级即父节点编码]]></supnodecode>
                                                                  <nodeurl><![cdata[节点关联链接地址]]></nodeurl>
                                                                  <iconexpand><![cdata[节点展开时显示图标路径]]></iconexpand>  
                                                                  <iconcollapse><![cdata[节点收缩时显示图标路径]]></iconcollapse>  
                                                            </item>

                                                            ... ...
                                                        </root>


             3、通过插件对象 的方法   addnodeitem(nodeitem)      通过手工一条一条的添加节点项目(需要两步完成) 全部添加完成后
                                                      通过插件对象 maketree()    再手工调用此方法,则可以创建树

 

      第三:目录树内部重组上下级关系的事件方法  通过此方法,可以解决我们前端不再需要按照上下级关系来区分。

  1   _createtree: function () {    // 创建树html对象
  2                     // 初始化变量参数
  3                     this._sdptree.empty();       // 清空目录树内的所有内容
  4                     this._fnobject.focusnodecode = "";
  5                     this._mynodes = [];
  6                     this._hsnodes = new $.hashtable();
  7                     this._dtnodes = [];
  8                     var _tmnodes = [], f = this._fnobject, p = this._fnobject.options, _this = this;
  9 
 10                     // 重组目录节点(依次将所有的节点组成自己的树) 一次循环完成 提高效率
 11                     function renew_groupnodes(currnodes) {
 12                         // 重绘节点上下级关系
 13                         function renew_tree(renode) {
 14                             if (_tmnodes[renode.nodecode]) {
 15                                 for (var n = 0; n < _tmnodes[renode.nodecode].length; n++) {
 16                                     renode._childs[n] = _tmnodes[renode.nodecode][n];
 17                                     renode._childs[n]._parent = renode;
 18                                     renode._childs[n]._firstflag = (n == 0) ? true : false;
 19                                     renode._childs[n]._lastflag = (n == (_tmnodes[renode.nodecode].length - 1)) ? true : false;
 20                                     renode._childs[n]._havechild = (_tmnodes[_tmnodes[renode.nodecode][n].nodecode]) ? true : false;
 21                                     renode._childs[n]._nodelevel = renode._nodelevel + 1;
 22                                     renew_tree(_tmnodes[renode.nodecode][n]);  // 迭代循环
 23                                 }
 24                             }
 25                         };
 26 
 27                         var m = 0;
 28                         _tmnodes[p.rootcode] = [];   // 根节点
 29                         for (m = 0; m < currnodes.length; m++) {
 30                             var _nd = currnodes[m];
 31                             _tmnodes[_nd.supnodecode] = _tmnodes[_nd.supnodecode] || [];
 32                             _tmnodes[_nd.supnodecode].push(_nd);
 33                             _this._hsnodes.add(_nd.nodecode, _nd);
 34                         };
 35                         var _rtnodes = _tmnodes[p.rootcode];
 36 
 37                         for (m = 0; m < _rtnodes.length; m++) {
 38                             _this._dtnodes[m] = _rtnodes[m];
 39                             _this._dtnodes[m]._parent = null;
 40                             _this._dtnodes[m]._firstflag = (m == 0) ? true : false;  // 设置参数
 41                             _this._dtnodes[m]._lastflag = (m == (_rtnodes.length - 1)) ? true : false;
 42                             _this._dtnodes[m]._havechild = (_tmnodes[_rtnodes[m].nodecode]) ? true : false;
 43                             _this._dtnodes[m]._nodelevel = 1;
 44                             renew_tree(_rtnodes[m]);                               // 迭代循环
 45                         };
 46 
 47                         _rtnodes = null;
 48                         _tmnodes = null;
 49                     };
 50 
 51                     // 执行节点重组
 52                     renew_groupnodes(f.curnodes);
 53                     f.curnodes = [];  // 清空临时节点数组变量,便于后续重新加载使用
 54 
 55                     // 定义前缀字符
 56                     var full_prefix = this._myfnid + "_sdptree_node_full";     // 完整的一个节点div(包含:连线、+号图片、节点图片、选择框、节点文本)
 57                     var node_prefix = this._myfnid + "_sdptree_node_span";     // 节点span
 58                     // var plus_prefix = this._myfnid + "_sdptree_node_plus";     // + 号图片
 59                     var nimg_prefix = this._myfnid + "_sdptree_node_icon";     // 节点图片
 60                     var chkr_prefix = this._myfnid + "_sdptree_node_chk";      // 选择图片
 61                     var text_prefix = this._myfnid + "_sdptree_node_text";     // 节点文本
 62                     var clip_prefix = this._myfnid + "_sdptree_node_clip";     // 子节点div
 63 
 64                     // 注意点:前台传入的所有自定义的图标,全部已经是指定的完整路径了,所以这里就不需要转换
 65                     var _rootcode = p.rootcode;
 66                     if (p.showroot) {           // 判定是否显示根节点
 67                         var tmrhtml = [];
 68                         tmrhtml.push('<div id="' + full_prefix + '_' + _rootcode + '" stype="full" >');
 69                         tmrhtml.push('<span id="' + node_prefix + '_' + _rootcode + '" class="node_default" stype="node" >');
 70                         if (p.showicon) {
 71                             tmrhtml.push('<span id="' + nimg_prefix + '_' + _rootcode + '" stype="icon" ');
 72                             if (p.rooticon) {   // 是否客户自定义的图片
 73                                 tmrhtml.push('class="custom_img" style="background-image: url(' + (p.rooticon) + ');"');
 74                             } else {                                // 启用默认的样式图片
 75                                 tmrhtml.push('class="root_img"');
 76                             };
 77                             tmrhtml.push(' ></span>');
 78                         };
 79                         if (p.selecttype == "checkbox") {     // 是否开启选择按钮
 80                             tmrhtml.push('<span id="' + chkr_prefix + '_' + _rootcode + '" stype="check" class="checkbox"></span>');
 81                         } else if (p.selecttype == "radio") {
 82                             tmrhtml.push('<span id="' + chkr_prefix + '_' + _rootcode + '" stype="check" class="radiobtn"></span>');
 83                         };
 84                         tmrhtml.push('<span id="' + text_prefix + '_' + _rootcode + '"  class="root_title" stype="text">' + p.roottext + '</span>');
 85                         tmrhtml.push('</span>');
 86                         tmrhtml.push('</div>');
 87                         this._sdptree.append($(tmrhtml.join("")));
 88                         tmrhtml = null;
 89                     };
 90                     var $clipdom = null;
 91                     if (p.showroot) $clipdom = $('<div id="' + clip_prefix + '_' + _rootcode + '" class="clipdiv" stype="clip" style="display: block" ></div>');
 92                     var _rechtml = this._createnodes(this._dtnodes);
 93                     if (_rechtml) {
 94                         if ($clipdom) { $clipdom.append($(_rechtml)); this._sdptree.append($clipdom); } else { this._sdptree.append($(_rechtml)); };
 95                     } else {
 96                         if ($clipdom) { this._sdptree.append($clipdom); };
 97                     };
 98                     _rechtml = null;
 99 
100                     // 绑定事件
101                     this._bindevent();
102                     if (p.openall) { f.expandall(); };
103                 },

    

        第四:以上只是简单的介绍了一下tree的主要加载和重组方法。下面我们将完整的js插件代码贴出来,代码中有详细的注释

                  插件功能:复选、单选、展开、折叠、显示/隐藏节点连线 、支持插入节点、删除节点、节点小图标自定义、设置节点选中、获取目录树选择节点(支持xml,json等)

                                  右击菜单(暂时不支持,因为需要用到弹出层,这里就屏蔽删除了此功能)  支持节点单击、双击、节点选择改变事件等等

(function ($) {
    $.fn.webtree = function () {
        return {
            sdptype: "tree",           // 树形目录
            myobject: null,            // tree 树jquery对象 $("#treeid")
            mycontainer: null,         // tree 包围树节点的容器jquery对象[为了保证滚动条和位置的协调,特加入一个容器]
            myfnid: "",                // tree 内部使用id[目录树控件可以不定义id,此属性就是为无id的情况下也能适用]
            sdptree: null,             // tree 插件自动生成树节点的包围容器,与mycontainer 容器非同一个容器,是在mycontainer的内部
            focusnodecode: null,       // tree 树当前获取到焦点的节点编码
            defaults: {                // tree 树默认相关参数
                sdpfixed: false,       // tree 是否设计器设计的固定目录树
                showroot: true,        // tree 是否显示根目录
                showline: true,        // tree 是否显示连接竖线
                showicon: true,        // tree 是否显示节点图片
                selecttype: "",        // tree 树节点选择类型 "":表示无选择按钮; checkbox:表示启用复选按钮; radio:表示启用单选按钮
                cascade: false,        // tree 开启复选按钮时,是否启用级联选择(自动勾选下级及所属上级)
                popmenu: false,        // tree 是否启用右击弹出菜单
                openall: false,        // tree 是否展开所有节点;false: 展开第一级
                rooticon: "",          // tree 根目录节点自定义显示图标文件完整路径名称 [平台设计的则放在对应的图片目录中]
                middefticon: "",       // tree 中间节点收缩自定显示图标文件完整路径名称
                midexpdicon: "",       // tree 中间节点展开自定显示图标文件完整路径名称
                endnodeicon: "",       // tree 末级节点显示自定显示图标文件完整路径名称
                customload: "",        // tree 树自定加载事件(事件名称字符串或事件方法)[主要目的:为了让右击刷新按钮能找到重新加载数据的源头方法]
                nodeclick: "",         // tree 树目录节点单击事件(事件名称字符串或事件方法)
                nodedblclick: "",      // tree 树目录节点双击事件(事件名称字符串或事件方法)
                checkedchange: "",     // tree 树目录节点选择改变事件(事件名称字符串或事件方法)[只有开启了选择,才有效]
                rootcode: "-1",        // tree 根节点code id(目的是为支持从中间节点进行加载目录树的功能)默认为-1
                roottext: "树形目录",  // tree 根目录节点名称
                rooturl: ""            // tree 根目录超连接url地址
            },
            options: {},               // tree 控件最终参数
            curnodes: [],              // tree 临时树节点数组(添加节点时临时储存)

            // @ method: init() 插件实例初始化
            // @ depict: 执行插件实例的初始化
            // @ params: [object] element 控件对象
            // @ pbtype: 外部调用方法
            init: function (element) {        // 树初始化
                this.myobject = $(element);
                if (this.myobject.length == 0) { return; };
                this.mycontainer = this.myobject.children('div[sdptype="treebase"]');
                if (this.mycontainer.length == 0) { // 重新创建
                    this.myobject.empty().append('<div sdptype="treebase" class="sdp-tree-base" ></div>');
                    this.mycontainer = this.myobject.children('div[sdptype="treebase"]');
                };
                this.myfnid = this.myobject.attr("id") || $.newguid();               // tree 内部使用id 用于创建node各个节点
                this.mycontainer.empty().append('<div class="sdp-tree-in"></div>');  // 添加一个正式的目录树容器
                this.sdptree = this.mycontainer.find("div.sdp-tree-in");             // 获取sdptree容器jquery对象

                // 设置内部参数
                this._methods._fnobject = this;
                this._methods._myobject = this.myobject;
                this._methods._mycontainer = this.mycontainer;
                this._methods._myfnid = this.myfnid;
                this._methods._sdptree = this.sdptree;

                // 加载绑定参数
                this._loadparam();
                this._bindevent();
            },

            // @ method: setoptions() 自定设置控件options属性值
            // @ depict: 自定设置控件options属性值
            // @ params: [object] options 树形配置参数 json格式
            // @ pbtype: 外部调用方法
            setoptions: function (options) {
                if (!options) { options = {}; };
                this.options = $.extend({}, this.options, options);  // 合并目录树相关参数
            },

            // @ method: nodeitem() 创建一个空节点参数对象
            // @ depict: 通过此方法创建一个空节点参数对象,用于前台初始化增加节点或执行插入节点使用,通过扩展方法来组合参数
            // @ return: [array]节点{  // 节点参数
            // @                       nodecode: "",         // string  节点编码 
            // @                       nodetext: "",         // string  节点名称文本 
            // @                       nodetitle: "",        // string  节点鼠标移入显示提示文本
            // @                       supnodecode: "",      // string  节点所属上级即父节点编码
            // @                       nodeurl: "",          // string  节点关联链接地址
            // @                       iconexpand: "",       // string  节点展开时显示图标完整路径
            // @                       iconcollapse: ""      // string  节点收缩时显示图标完整路径
            // @                     }
            // @ pbtype: 外部调用方法
            nodeitem: function () {
                return {
                    nodecode: "",
                    nodetext: "",
                    nodetitle: "",
                    supnodecode: "",
                    nodeurl: "",
                    iconexpand: "",     // 节点展开时显示图标完整路径
                    iconcollapse: ""    // 节点收缩时显示图标完整路径
                };
            },


            // 创建树形目录
            // 由开发人员通过以下3种方式创建树数据
            // 1、loadjson(json)             json 对象目录树节点数组(一次性完成)
            // 2、loadxml(xml)               xml字符串格式的节点数据(一次性完成)
            // 3、addnodeitem(nodeitem)      通过手工一条一条的添加节点项目(需要两步完成)
            // 3、maketree()                 再手工调用此方法,则可以创建树

            // @ method: addnodeitem() 添加目录树节点
            // @ depict: 通过此方法向目录树添加节点数据
            // @ params: [array] nodeitem{} 格式参数数组
            // @ pbtype: 外部调用方法
            addnodeitem: function (nodeitem) {
                var _curnodeitem = $.extend({}, new this.nodeitem(), nodeitem);   // 合并参数
                if ($.isnull(_curnodeitem.nodecode)) { return; };
                if ($.isnull(_curnodeitem.supnodecode)) { _curnodeitem.supnodecode = this.options.rootcode; };
                this.curnodes[this.curnodes.length] = {                           // 在临时树节点数组中添加待加入的节点信息
                    nodecode: _curnodeitem.nodecode,
                    nodetext: _curnodeitem.nodetext || "",
                    nodetitle: _curnodeitem.nodetitle || "",
                    supnodecode: _curnodeitem.supnodecode,
                    nodeurl: _curnodeitem.nodeurl || "",
                    iconexpand: _curnodeitem.iconexpand || "",
                    iconcollapse: _curnodeitem.iconcollapse || "",
                    _parent: null,            // 所属的父节点 
                    _firstflag: false,        // 本级中的首位 标志
                    _lastflag: false,         // 本级中的末位 标志
                    _nodelevel: 0,            // 当前节点级别 默认0
                    _havechild: false,        // 是否包含下级
                    _childs: []               // 子节点的数组
                };
                _curnodeitem = null;
            },

            // @ method: loadxml() 加载xml格式的节点数据
            // @ depict: 直接加载解析xml格式的节点数据
            // @ params: [object] xml xml格式的节点字符串或xmldocument对象
            // @ pbtype: 外部调用方法
            loadxml: function (xml) {
                if ($.isnull(this.options.rootcode)) { this.options.rootcode = "-1"; }; // 设置根节点编码
                this.curnodes = [];                                                     // 清空变量数据
                if (xml) {
                    var currxmldoc = null;
                    if (typeof (xml) == "object") {
                        currxmldoc = xml;
                    } else {                          //   string
                        currxmldoc = $.loadxmlstring(string(xml));
                    };
                    if (currxmldoc) {               // 再次判定  开始解析
                        for (var nn = 0; nn < currxmldoc.documentelement.childnodes.length; nn++) {
                            var _curnode = currxmldoc.documentelement.childnodes[nn];
                            var _curadditem = new this.nodeitem();
                            for (var jj = 0; jj < _curnode.childnodes.length; jj++) {
                                var _subitem = _curnode.childnodes[jj];
                                switch (_subitem.tagname.tolowercase()) {
                                    case "nodecode":
                                        _curadditem.nodecode = $(_subitem).text();
                                        break;
                                    case "nodetext":
                                        _curadditem.nodetext = $(_subitem).text();
                                        break;
                                    case "nodetitle":
                                        _curadditem.nodetitle = $(_subitem).text();
                                        break;
                                    case "supnodecode":
                                        _curadditem.supnodecode = $(_subitem).text();
                                        break;
                                    case "nodeurl":
                                        _curadditem.nodeurl = $(_subitem).text();
                                        break;
                                    case "iconexpand":
                                        _curadditem.iconexpand = $(_subitem).text();
                                        break;
                                    case "iconcollapse":
                                        _curadditem.iconcollapse = $(_subitem).text();
                                        break;
                                };
                            };

                            this.addnodeitem(_curadditem);
                        }
                    }
                };

                this.maketree();

                // 说明:采用xml字符串格式
                // <root>
                //    <item>   // 每一个节点 内包含多个数据值   
                //        <nodecode><![cdata[节点编码值]]></nodecode>";          注意节点 tagname:nodecode nodetext 等 不允许变更 因为程序内部是直接采用这个名字来获取的         
                //        <nodetext><![cdata[节点名称文本 ]]></nodetext>";  
                //        <nodetitle><![cdata[节点鼠标移入显示提示文本]]></nodetitle>";  
                //        <supnodecode><![cdata[节点所属上级即父节点编码]]></supnodecode>";  
                //        <nodeurl><![cdata[节点关联链接地址]]></nodeurl>"; 
                //        <iconexpand><![cdata[节点展开时显示图标路径]]></iconexpand>";  
                //        <iconcollapse><![cdata[节点收缩时显示图标路径]]></iconcollapse>";  
                //    </item>
                //</root>
            },

            // @ method: loadjson() 加载json格式的节点数据
            // @ depict: 直接加载解析json格式的节点数据
            // @ params: [array] json json数据对象
            // @ pbtype: 外部调用方法
            loadjson: function (json) {
                if (!this.options.rootcode) { this.options.rootcode = "-1"; };            // 设置根节点编码
                this.curnodes = [];                                                       // 清空变量数据
                if (json) {
                    for (var jj = 0; jj < json.length; jj++) {
                        var jsonitem = json[jj];
                        if (!jsonitem.nodecode) { continue; };   // 节点编码不允许为空

                        var addsitem = new this.nodeitem();
                        addsitem.nodecode = jsonitem.nodecode;
                        addsitem.nodetext = jsonitem.nodetext || "";
                        addsitem.nodetitle = jsonitem.nodetitle || "";
                        addsitem.supnodecode = jsonitem.supnodecode || "";
                        addsitem.nodeurl = jsonitem.nodeurl || "";
                        addsitem.iconexpand = jsonitem.iconexpand || "";
                        addsitem.iconcollapse = jsonitem.iconcollapse || "";

                        this.addnodeitem(addsitem);   // 添加节点 
                    };
                };
                this.maketree();

                // json 格式 是一个array 数组 每项为一个 nodeitem 对象的参数
                // [{ nodecode: "", nodetext: "", nodetitle: "",supnodecode: "",nodeurl: "",iconexpand: "",iconcollapse: ""},
                //   {},...
                // ]
            },

            // @ method: loadnodeitems() 加载nodeitem array节点数组数据
            // @ depict: 直接加载nodeitem array节点数组数据
            // @ params: [array] itemarray nodeitem array节点数组数据
            // @ pbtype: 外部调用方法
            loadnodeitems: function (itemarray) {
                if (!itemarray) { itemarray = []; };
                for (var jj = 0; jj < itemarray.length; jj++) {
                    var nditem = itemarray[jj];
                    if (!nditem.nodecode) { continue; };   // 节点编码不允许为空
                    this.addnodeitem(nditem);              // 添加节点 
                };
                this.maketree();
            },

            // @ method: maketree() 创建生成树
            // @ depict: 创建生成树对象的所有节点并显示出来
            // @         此方法执行之前需要先获取或手工添加完成所有树节点
            // @         前台js 必须通过 addnodeitem(nodeitem) 方法添加节点
            // @ pbtype: 外部内部调用方法
            maketree: function () {
                this.sdptree.empty();
                this._methods._createtree();
            },

            // @ method: appendnode() 插入节点
            // @ depict: 通过此方法向目录树插入新的节点
            // @ params: [array] nodeitem {} 格式参数数组
            // @ pbtype: 外部调用方法
            appendnode: function (nodeitem) {
                var _this = this, p = this.options;
                var curnewnode = $.extend({}, new this.nodeitem(), nodeitem);          // 合并节点输入参数
                if ($.isnull(curnewnode.nodecode)) { return; };
                if ($.isnull(curnewnode.supnodecode)) { curnewnode.supnodecode = p.rootcode; };
                if (this._methods._hsnodes[curnewnode.nodecode]) { return; };          // 节点编码已经存在,不执行添加
                if (p.rootcode != curnewnode.supnodecode && !this._methods._hsnodes[curnewnode.supnodecode]) { return; };  // 父节点不为根节点时,父节点数据不存在,则不执行
                var newnode = {
                    nodecode: curnewnode.nodecode,
                    nodetext: curnewnode.nodetext || "",
                    nodetitle: curnewnode.nodetitle || "",
                    supnodecode: curnewnode.supnodecode,
                    nodeurl: curnewnode.nodeurl || "",
                    iconexpand: curnewnode.iconexpand || "",
                    iconcollapse: curnewnode.iconcollapse || "",
                    _parent: null,            // 所属的父节点 
                    _firstflag: false,        // 本级中的首位 标志
                    _lastflag: false,         // 本级中的末位 标志
                    _nodelevel: 0,            // 当前节点级别 默认0
                    _havechild: false,        // 是否包含下级
                    _childs: []               // 子节点的数组
                };
                curnewnode = null;
                if (p.rootcode == newnode.supnodecode) {
                    newnode._parent = null;
                    newnode._nodelevel = 1;
                    var len = this._methods._dtnodes.length;
                    if (len > 0) {
                        this._methods._dtnodes[len - 1]._lastflag = false;
                        newnode._lastflag = true;
                    } else {
                        newnode._firstflag = true;
                        newnode._lastflag = true;
                    };
                    this._methods._dtnodes.push(newnode);   // 添加到第一级中
                } else {
                    var curparent = this._methods._hsnodes[newnode.supnodecode];
                    newnode._parent = curparent;
                    newnode._nodelevel = curparent._nodelevel + 1;
                    if (curparent._havechild) {
                        curparent._childs[curparent._childs.length - 1]._lastflag = false;
                        newnode._lastflag = true;
                    } else {
                        curparent._havechild = true;
                        newnode._firstflag = true;
                        newnode._lastflag = true;
                    };
                    curparent._childs.push(newnode);  // 添加到父节点的子节点数组中
                };
                this._methods._hsnodes.add(newnode.nodecode, newnode);  // 加入hash

                // 创建节点
                var curnodes = []; curnodes.push(newnode);
                var $appnode = $(this._methods._createnodes(curnodes));
                if (newnode.nodecode == p.rootcode) {
                    if (p.showroot) { this.sdptree.find("#" + this.myfnid + "_sdptree_node_clip_" + p.rootcode).append($appnode); } else { this.sdptree.append($appnode); };
                } else {
                    var $parent_clip = this.sdptree.find("#" + this.myfnid + "_sdptree_node_clip_" + newnode.supnodecode);
                    if ($parent_clip.length > 0) {
                        $parent_clip.append($appnode);
                    }
                    else {
                        $now_clip = $('<div id="' + this.myfnid + '_sdptree_node_clip_' + newnode.supnodecode + '" class="clipdiv" stype="clip" style="display: block" ></div>');
                        $now_clip.append($appnode);
                        this.sdptree.find("#" + this.myfnid + "_sdptree_node_full_" + newnode.supnodecode).after($now_clip);
                    };
                };

                // 更新节点样式
                if (newnode.supnodecode == p.rootcode) {   // 上级为根节点的时候,直接更新前一个节点    
                    if (this._methods._dtnodes.length > 1) {
                        var _prevcode = this._methods._dtnodes[this._methods._dtnodes.length - 2].nodecode;
                        this._methods._updatenode(_prevcode);
                    };
                } else {                                             // 上级不为根节点时候,直接更新此上级节点
                    this._methods._updatenode(newnode.supnodecode);
                };

                // 绑定节点hover事件
                $appnode.find("span[stype='node']").hover(function () {
                    var tmtitle = _this._methods._hsnodes[$(this).attr("id").replace(_this.myfnid + "_sdptree_node_span_", "")].nodetitle;
                    if (!tmtitle) { tmtitle = $.text(this); };
                    $(this).addclass("node_hover").attr("title", tmtitle);
                }, function () {
                    $(this).removeclass("node_hover").attr("title", "");
                });
            },

            // @ method: deletenode()  删除树节点
            // @ depict: 删除指定节点编码的树节点
            // @ params: [string] nodecode 节点编码
            // @ pbtype: 外部调用方法
            deletenode: function (nodecode) {
                if ($.isnull(nodecode)) { return; };
                if (nodecode == this.options.rootcode) {
                    this.clearall();
                } else {
                    if (!this._methods._hsnodes[nodecode]) { return; };
                    var removenode = this._methods._hsnodes[nodecode];
                    var prevnodecode = this.getprevnodecode(nodecode);
                    var tm2 = 0;

                    // 首先删除hash表中的所有子节点 先不删除本身节点
                    if (removenode._havechild) {
                        for (var tm1 = 0; tm1 < removenode._childs.length; tm1++) {
                            this._methods._removehashnodes(removenode._childs[tm1].nodecode);
                        };
                    };

                    // 移除dtnodes数组中的节点项
                    if (removenode._parent) {
                        for (tm2 = 0; tm2 < removenode._parent._childs.length; tm2++) {
                            if (removenode._parent._childs[tm2].nodecode == nodecode) {
                                removenode._parent._childs.splice(tm2--, 1);
                                break;
                            };
                        };
                    } else {   // 根目录下的第一级
                        for (tm2 = 0; tm2 < this._methods._dtnodes.length; tm2++) {
                            if (this._methods._dtnodes[tm2].nodecode == nodecode) {
                                this._methods._dtnodes.splice(tm2--, 1);
                                break;
                            };
                        };
                    };

                    // 移除dom node对象
                    var rmnodefulldom = this.sdptree.find("#" + this.myfnid + "_sdptree_node_full_" + nodecode);
                    var rmnodeclipdom = this.sdptree.find("#" + this.myfnid + "_sdptree_node_clip_" + nodecode);
                    if (rmnodefulldom.length > 0) { rmnodefulldom.remove(); };
                    if (rmnodeclipdom.length > 0) { rmnodeclipdom.remove(); };

                    // 更新node父节点的数据
                    var parentnd = removenode._parent;
                    if (!parentnd) {
                        for (tm2 = 0; tm2 < this._methods._dtnodes.length; tm2++) {
                            this._methods._dtnodes[tm2]._firstflag = (tm2 == 0) ? true : false;
                            this._methods._dtnodes[tm2]._lastflag = (tm2 == (this._methods._dtnodes.length - 1)) ? true : false;
                        };
                    } else {
                        if (parentnd._childs.length > 0) {
                            for (tm2 = 0; tm2 < parentnd._childs.length; tm2++) {
                                parentnd._childs[tm2]._firstflag = (tm2 == 0) ? true : false;
                                parentnd._childs[tm2]._lastflag = (tm2 == (parentnd._childs.length - 1)) ? true : false;
                            };
                        } else {
                            parentnd._havechild = false;
                        };
                    };

                    this._methods._hsnodes.remove(removenode.nodecode);  // 从hash表删除自己

                    // 更新节点样式
                    if (parentnd) {
                        this._methods._updatenode(parentnd.nodecode);    // 更新父级节点显示样式
                    } else {
                        this._methods._updatenode(prevnodecode);         // 更新前一级节点显示样式
                    };
                };
            },

            // @ method: clearall()  清空树节点
            // @ depict: 清空树所有节点包括参数
            // @ pbtype: public 外部调用方法
            clearall: function () {
                this.focusnodecode = null;
                this.curnodes = [];
                this._methods._mynodes = [];
                this._methods._dtnodes = null;
                this._methods._hsnodes = null;
                this.sdptree.empty();
            },

            // @ method: getnode() 获取节点对象div
            // @ depict: 根据节点 nodecode 来获取 
            // @ params: [string] nodecode 节点编码
            // @ return: [object] 返回节点dom元素对象
            // @ pbtype: 外部调用方法
            getnode: function (nodecode) {
                var retnode = this.sdptree.find("#" + this.myfnid + "_sdptree_node_full_" + nodecode);
                return ((retnode.length > 0) ? retnode[0] : null);
            },

            // @ method: getnodeparams() 获取节点的所有参数
            // @ depict: 根据节点 nodecode 来获取 
            // @ params: [string] nodecode 节点编码
            // @ return: [object] 返回节点参数对象
            // @ pbtype: 外部调用方法
            getnodeparams: function (nodecode) {
                var retnodeitem = null;
                if (nodecode == null) { return retnodeitem; };
                if (nodecode == this.options.rootcode) {               // 树根节点
                    retnodeitem = new this.nodeitem();
                    retnodeitem.nodecode = this.options.rootcode;
                    retnodeitem.nodetext = this.options.roottext;
                    retnodeitem.nodeurl = this.options.rooturl;
                    retnodeitem.iconcollapse = this.options.rooticon;
                } else {                                               // 普通节点
                    retnodeitem = this._methods._hsnodes[nodecode];    // 从数组中获取此节点的所有值
                };
                return retnodeitem;
            },

            // @ method: getnodecode() 获取节点编码
            // @ depict: 根据节点对象(通过getnode() 方法获取的节点对象) 来获取此对象的节点id
            // @ params: node  object 节点dom对象
            // @ return: string  返回节点对象的id
            // @ pbtype: 外部调用方法
            getnodecode: function (node) {
                var retnodecode = null;
                if (node) {
                    var tmid = $(node).attr("id");
                    if (tmid) {
                        retnodecode = tmid.replace(this.myfnid + "_sdptree_node_full_", "");
                    };
                };
                return retnodecode;
            },

            // @ method: getprevnodecode() 获取指定节点的前一个节点的节点编码nodecode
            // @ depict: 根据指定的节点nodecode来获取其前一个节点nodecode 节点编码
            // @ params: nodecode  string 指定的节点编码
            // @ return: string  返回指定的节点nodecode的前一个节点编码nodecode
            // @ pbtype: 外部调用方法
            getprevnodecode: function (nodecode) {
                var _prevcode = null;
                var _curtnode = this._methods._hsnodes[nodecode];
                if (_curtnode) {
                    if (_curtnode._firstflag) { return _prevcode; };
                    if (_curtnode.supnodecode == this.options.rootcode) {
                        for (var tm0 = 0; tm0 < this._methods._dtnodes.length; tm0++) {
                            if (this._methods._dtnodes[tm0].nodecode == nodecode) {
                                _prevcode = this._methods._dtnodes[tm0 - 1].nodecode;
                                break;
                            };
                        };
                    } else {
                        var _parentnd = _curtnode._parent;
                        for (var tm1 = 0; tm1 < _parentnd._childs.length; tm1++) {
                            if (_parentnd._childs[tm1].nodecode == nodecode) {
                                _prevcode = _parentnd._childs[tm1 - 1].nodecode;
                                break;
                            };
                        };
                    };
                };
                return _prevcode;
            },

            // @ method: getnextnodecode() 获取指定节点的下一个节点编码
            // @ depict: 根据指定的节点编码来获取其后一个节点编码nodecode
            // @ params: nodecode  string 指定的节点编码
            // @ return: object  返回指定的节点的后一个节点编码字符串
            // @ pbtype: 外部调用方法
            getnextnodecode: function (nodecode) {
                var _nextcode = null;
                var _curtnode = this._methods._hsnodes[nodecode];
                if (_curtnode) {
                    if (_curtnode._lastflag) { return _nextcode; };
                    if (_curtnode.supnodecode == this.options.rootcode) {
                        for (var tm0 = 0; tm0 < this._methods._dtnodes.length; tm0++) {
                            if (this._methods._dtnodes[tm0].nodecode == nodecode) {
                                _nextcode = this._methods._dtnodes[tm0 + 1].nodecode;
                                break;
                            };
                        };
                    } else {
                        var _parentnd = _curtnode._parent;
                        for (var tm1 = 0; tm1 < _parentnd._childs.length; tm1++) {
                            if (_parentnd._childs[tm1].nodecode == nodecode) {
                                _nextcode = _parentnd._childs[tm1 + 1].nodecode;
                                break;
                            };
                        };
                    };
                };
                return _nextcode;
            },

            // @ method: getparentnodecode() 获取指定节点的父级节点编码
            // @ depict: 根据节点编码来获取其父级节点编码
            // @ params: nodecode  string 指定的节点编码
            // @ return: string  返回指定的节点编码的父级节点编码
            // @ pbtype: 外部调用方法
            getparentnodecode: function (nodecode) {
                var _parentnodecode = null;
                if (this._methods._hsnodes[nodecode]) {
                    _parentnodecode = this._methods._hsnodes[nodecode].supnodecode;
                };
                return _parentnodecode;
            },

            // @ method: getfocusnodecode() 获取目录树当前获取到焦点的节点编码
            // @ depict: 获取当前目录中,获取到焦点的即选中的节点编码 nodecode
            // @ return: string  返回节点编码字符串
            // @ pbtype: 外部调用方法
            getfocusnodecode: function () {
                return this.focusnodecode;
            },

            // @ method: getnodelevel() 获取节点级别层次
            // @ depict: 根据节点编码来获取 此节点的层次级别
            // @ params: nodecode  string 节点编码
            // @ return: number 节点层次级别,无效返回-1
            // @ pbtype: 外部调用方法
            getnodelevel: function (nodecode) {
                if (nodecode == this.options.rootcode) {
                    return 0;
                } else {
                    if (this._methods._hsnodes[nodecode]) {
                        return (this._methods._hsnodes[nodecode])._nodelevel;
                    } else {
                        return -1;
                    };
                };
            },

            // @ method: getnodetext() 获取节点文本值
            // @ depict: 根据节点编码来获取节点文本值
            // @ params: nodecode  string 节点编码
            // @ return: string 节点文本值
            // @ pbtype: 外部调用方法
            getnodetext: function (nodecode) {
                var tm_node = this.getnode(nodecode);
                if (tm_node) { return $(tm_node).text(); };
                return null;
            },

            // @ method: getnodeval() 获取节点所有值
            // @ depict:根据节点编码 获取节点的所有值
            // @ params: nodecode  string 节点编码
            // @ return: array {} 节点数据数组对象
            // @ pbtype:  外部调用方法
            getnodeval: function (nodecode) {
                var curnodeitem = new this.nodeitem();
                if (nodecode == this.options.rootcode) {
                    curnodeitem.nodecode = this.options.rootcode;
                    curnodeitem.nodetext = this.options.roottext;
                    curnodeitem.nodetitle = "";
                    curnodeitem.supnodecode = "";
                    curnodeitem.nodeurl = this.options.rooturl;
                    curnodeitem.iconexpand = this.options.rooticon;
                    curnodeitem.iconcollapse = this.options.rooticon;
                } else {
                    var tm_node = this._methods._hsnodes[nodecode];
                    if (tm_node) {
                        curnodeitem.nodecode = tm_node.nodecode;
                        curnodeitem.nodetext = tm_node.nodecode;
                        curnodeitem.nodetitle = tm_node.nodecode;
                        curnodeitem.supnodecode = tm_node.nodecode;
                        curnodeitem.nodeurl = tm_node.nodeurl;
                        curnodeitem.iconexpand = tm_node.iconexpand;
                        curnodeitem.iconcollapse = tm_node.iconcollapse;
                    };
                };
                return curnodeitem;
            },

            // @ method: hidenode() 隐藏指定节点
            // @ depict: 根据节点编码 执行隐藏指定树节点对象
            // @ params: nodecode  string 节点编码
            // @ pbtype: 外部调用方法
            hidenode: function (nodecode) {
                if (this.options.rootcode == nodecode) { return; };
                var tm_mynode = this.getnode(nodecode);
                if (!tm_mynode) { return; };
                var tm_subnode = this.sdptree.find("#" + this.myfnid + "_sdptree_node_clip_" + nodecode);
                $(tm_mynode).hide();
                if (tm_subnode.length > 0) { $(tm_subnode).hide(); };
            },

            // @ method: shownode() 显示指定节点
            // @ depict: 根据节点编码 执行显示指定树节点对象
            // @ params: nodecode  string 节点编码
            // @ pbtype: 外部调用方法
            shownode: function (nodecode) {
                if (this.options.rootcode == nodecode) { return; };
                var tm_mynode = this.getnode(nodecode);
                if (tm_mynode) {
                    $(tm_mynode).show();
                    this.collapsenode(nodecode);
                };
            },

            // @ method: setshowtreeline() 设置树节点连线显示与否
            // @ depict: 设置显示、隐藏节点连线 [此功能只有当树期初设置为显示树节点连线的时候才起作用]
            // @ params: boolvalue  boolean  说明:true 表示显示连接线  false 表示不显示
            // @ pbtype: 外部调用方法
            setshowtreeline: function (boolvalue) {
                if (!this.options.showline) { return; };
                var pluslist = this.sdptree.find("span[stype='plus']");
                var linelist = this.sdptree.find("span[stype='line']");
                var tm0 = 0;
                if ((boolvalue) && boolvalue == true) {
                    for (tm0 = 0; tm0 < pluslist.length; tm0++) {
                        if ($(pluslist[tm0]).prop("open")) {
                            if ($(pluslist[tm0]).hasclass("node_expd_0n")) {
                                switch ($(pluslist[tm0]).attr("collclass")) {
                                    case "node_plug_1l":
                                        $(pluslist[tm0]).removeclass("node_plug_0n");
                                        $(pluslist[tm0]).removeclass("node_expd_0n");
                                        $(pluslist[tm0]).addclass("node_plug_1l");
                                        $(pluslist[tm0]).addclass("node_expd_1l");
                                        break;
                                    case "node_plug_2b":
                                        $(pluslist[tm0]).removeclass("node_plug_0n");
                                        $(pluslist[tm0]).removeclass("node_expd_0n");
                                        $(pluslist[tm0]).addclass("node_plug_2b");
                                        $(pluslist[tm0]).addclass("node_expd_2b");
                                        break;
                                    case "node_plug_2t":
                                        $(pluslist[tm0]).removeclass("node_plug_0n");
                                        $(pluslist[tm0]).removeclass("node_expd_0n");
                                        $(pluslist[tm0]).addclass("node_plug_2t");
                                        $(pluslist[tm0]).addclass("node_expd_2t");
                                        break;
                                    case "node_plug_3a":
                                        $(pluslist[tm0]).removeclass("node_plug_0n");
                                        $(pluslist[tm0]).removeclass("node_expd_0n");
                                        $(pluslist[tm0]).addclass("node_plug_3a");
                                        $(pluslist[tm0]).addclass("node_expd_3a");
                                        break;
                                }
                            }
                        } else {
                            if ($(pluslist[tm0]).hasclass("node_plug_0n")) {
                                $(pluslist[tm0]).removeclass("node_plug_0n");
                                $(pluslist[tm0]).addclass($(pluslist[tm0]).attr("collclass"));
                            }
                        }
                    };
                    for (tm0 = 0; tm0 < linelist.length; tm0++) {
                        if (($(linelist[tm0]).hasclass("node_line_10")) && ($(linelist[tm0]).hasclass("nullimg"))) { $(linelist[tm0]).removeclass("nullimg"); };
                        if (($(linelist[tm0]).hasclass("node_line_11")) && ($(linelist[tm0]).hasclass("nullimg"))) { $(linelist[tm0]).removeclass("nullimg"); };
                        if (($(linelist[tm0]).hasclass("node_line_20")) && ($(linelist[tm0]).hasclass("nullimg"))) { $(linelist[tm0]).removeclass("nullimg"); };
                        if (($(linelist[tm0]).hasclass("node_line_21")) && ($(linelist[tm0]).hasclass("nullimg"))) { $(linelist[tm0]).removeclass("nullimg"); };
                        if (($(linelist[tm0]).hasclass("node_line_3n")) && ($(linelist[tm0]).hasclass("nullimg"))) { $(linelist[tm0]).removeclass("nullimg"); };
                    };
                } else {
                    for (tm0 = 0; tm0 < pluslist.length; tm0++) {
                        var $plusobj = $(pluslist[tm0]);
                        if ($plusobj.prop("open")) {
                            if ($plusobj.hasclass("node_expd_1l")) {
                                $plusobj.removeclass("node_plug_1l").removeclass("node_expd_1l").addclass("node_plug_0n").addclass("node_expd_0n").attr("collclass", "node_plug_1l");
                            } else if ($plusobj.hasclass("node_expd_2b")) {
                                $plusobj.removeclass("node_plug_2b").removeclass("node_expd_2b").addclass("node_plug_0n").addclass("node_expd_0n").attr("collclass", "node_plug_2b");
                            } else if ($plusobj.hasclass("node_expd_2t")) {
                                $plusobj.removeclass("node_plug_2t").removeclass("node_expd_2t").addclass("node_plug_0n").addclass("node_expd_0n").attr("collclass", "node_plug_2t");
                            } else if ($plusobj.hasclass("node_expd_3a")) {
                                $plusobj.removeclass("node_plug_3a").removeclass("node_expd_3a").addclass("node_plug_0n").addclass("node_expd_0n").attr("collclass", "node_plug_3a");
                            };
                        } else {
                            if ($plusobj.hasclass("node_plug_1l")) {
                                $plusobj.removeclass("node_plug_1l").addclass("node_plug_0n").attr("collclass", "node_plug_1l");
                            } else if ($plusobj.hasclass("node_plug_2b")) {
                                $plusobj.removeclass("node_plug_2b").addclass("node_plug_0n").attr("collclass", "node_plug_2b");
                            } else if ($plusobj.hasclass("node_plug_2t")) {
                                $plusobj.removeclass("node_plug_2t").addclass("node_plug_0n").attr("collclass", "node_plug_2t");
                            } else if ($plusobj.hasclass("node_plug_3a")) {
                                $plusobj.removeclass("node_plug_3a").addclass("node_plug_0n").attr("collclass", "node_plug_3a");
                            };
                        };
                    };
                    for (tm0 = 0; tm0 < linelist.length; tm0++) {
                        var $lineobj = $(linelist[tm0]);
                        if (($lineobj.hasclass("node_line_10")) && (!$lineobj.hasclass("nullimg"))) { $lineobj.addclass("nullimg"); };
                        if (($lineobj.hasclass("node_line_11")) && (!$lineobj.hasclass("nullimg"))) { $lineobj.addclass("nullimg"); };
                        if (($lineobj.hasclass("node_line_20")) && (!$lineobj.hasclass("nullimg"))) { $lineobj.addclass("nullimg"); };
                        if (($lineobj.hasclass("node_line_21")) && (!$lineobj.hasclass("nullimg"))) { $lineobj.addclass("nullimg"); };
                        if (($lineobj.hasclass("node_line_3n")) && (!$lineobj.hasclass("nullimg"))) { $lineobj.addclass("nullimg"); };
                    };
                };
            },

            // @ method: setshownodeicon() 设置树节点icon小图标显示与否
            // @ depict:设置树节点是否显示icon小图标
            // @ params: boolvalue  boolean  说明:true 表示显示  false 表示不显示
            // @ pbtype: 外部调用方法
            setshownodeicon: function (boolvalue) {
                var tmdisplay = ((boolvalue) && boolvalue == true) ? "inline-block" : "none";
                var tmicons = this.sdptree.find("span[stype='icon']");
                for (var tm0 = 0; tm0 < tmicons.length; tm0++) { $(tmicons[tm0]).css("display", tmdisplay); };
            },

            // @ method: setshowselectbox() 设置树节点选择按钮显示与否
            // @ depict:设置树节点是否显示选择按钮(复选框或单选框)
            // @ params: [string]  checktype  显示按钮类型:空、radio、checkbox
            // @ pbtype: 外部调用方法
            setshowselectbox: function (checktype) {
                if (!checktype) { checktype = ""; };
                if (checktype == "checkbox") {
                    this.options.selecttype = "checkbox";
                } else if (checktype == "radio") {
                    this.options.selecttype = "radio";
                } else {
                    this.options.selecttype = "";
                };

                var tmchecknodes = null;
                if (this.options.selecttype) {
                    tmchecknodes = this.sdptree.find("span[stype='check']");
                    if (tmchecknodes.length > 0) { tmchecknodes.remove(); };
                    tmchecknodes = this.sdptree.find("span[stype='node']");
                    for (var tm0 = 0; tm0 < tmchecknodes.length; tm0++) {
                        var tm_titlenode = $(tmchecknodes[tm0]).find("span[stype='text']");
                        var tm_nodeid = tm_titlenode.attr("id").replace(this.myfnid + "_sdptree_node_text_", "");
                        if (this.options.selecttype == "checkbox") {
                            $(tm_titlenode).before('<span class="checkbox" stype="check" id="' + this.myfnid + '_sdptree_node_chk_' + tm_nodeid + '" ></span>');
                        } else {
                            $(tm_titlenode).before('<span class="radiobtn" stype="check" id="' + this.myfnid + '_sdptree_node_chk_' + tm_nodeid + '" ></span>');
                        };
                    };

                } else {
                    tmchecknodes = this.sdptree.find("span[stype='check']");
                    if (tmchecknodes.length > 0) { tmchecknodes.remove(); };
                }
            },

            // @ method: checkedall() 全部选中
            // @ depict: 当树开始复选时,实现选中全部树节点 
            // @ pbtype: 外部调用方法
            checkedall: function () {
                var _chkicon = this.sdptree.find("#" + this.myfnid + "_sdptree_node_chk_" + this.options.rootcode);
                if ((_chkicon) && _chkicon.length > 0) {
                    this._methods._checkednodes(_chkicon, true, true);
                }
            },

            // @ method: uncheckall() 取消选择
            // @ depict: 当树开始复选时,实现取消全部全部树节点的选中 
            // @ pbtype: 外部调用方法
            uncheckall: function () {
                var _chkicon = this.sdptree.find("#" + this.myfnid + "_sdptree_node_chk_" + this.options.rootcode);
                if ((_chkicon) && _chkicon.length > 0) {
                    this._methods._checkednodes(_chkicon, false, true);
                }
            },

            // @ method: setonenodechecked() 设置节点选中与否 注意:此方法只设置此单个的节点
            // @ depict: 根据节点编码来设置节点选择与否 只设置一个节点,下级不进行设置
            // @ params: [string] nodecode  节点编码
            // @ params: [bool]   boolchecked 是否选中 说明:true 表示显示  false 表示不显示
            // @ pbtype: 外部调用方法
            setonenodechecked: function (nodecode, boolchecked) {
                var boolval = (boolchecked) ? true : false;
                var chkimg = this.sdptree.find("#" + this.myfnid + "_sdptree_node_chk_" + nodecode);
                if ((chkimg) && chkimg.length > 0) {
                    if (boolval == chkimg.prop("checked")) { return; };
                    if (this.options.selecttype == "radio") {
                        if (boolval) {
                            var rdoallicon = this.sdptree.find("span[stype='check']");
                            for (var _tt = 0; _tt < rdoallicon.length; _tt++) {
                                var _curradio = $(rdoallicon[_tt]);
                                if (_curradio.prop("checked")) {
                                    _curradio.prop("checked", false).removeclass("radiobtn").removeclass("radiobtn_check").addclass("radiobtn");
                                };
                            };
                            chkimg.prop("checked", true).removeclass("radiobtn").removeclass("radiobtn_check").addclass("radiobtn_check");
                        } else {
                            chkimg.prop("checked", false).removeclass("radiobtn").removeclass("radiobtn_check").addclass("radiobtn");
                        }
                    } else if (this.options.selecttype == "checkbox") {
                        chkimg.removeclass("checkbox").removeclass("checkbox_check").addclass(((boolval) ? "checkbox_check" : "checkbox")).prop("checked", boolval);
                    };
                };
            },

            // @ method: setnodechecked() 设置节点选中与否 注意:此方法会自动设置下级(根据级联选择的原则)
            // @ depict: 根据节点编码来设置节点选择与否 
            // @ params: [string] nodecode  节点编码
            // @ params: [bool]   boolvalue 是否选中 说明:true 表示显示  false 表示不显示
            // @ pbtype: 外部调用方法
            setnodechecked: function (nodecode, boolvalue) {
                var boolval = (boolvalue) ? true : false;
                var chkimg = this.sdptree.find("#" + this.myfnid + "_sdptree_node_chk_" + nodecode);
                if ((chkimg) && chkimg.length > 0) {
                    if (this.options.selecttype == "radio") {
                        if (boolval == chkimg.prop("checked")) { return; };
                        if (boolval) {
                            var rdoallicon = this.sdptree.find("span[stype='check']");
                            for (var _tt = 0; _tt < rdoallicon.length; _tt++) {
                                var _curradio = $(rdoallicon[_tt]);
                                if (_curradio.prop("checked")) {
                                    _curradio.prop("checked", false).removeclass("radiobtn").removeclass("radiobtn_check").addclass("radiobtn");
                                };
                            };
                            chkimg.prop("checked", true).removeclass("radiobtn").removeclass("radiobtn_check").addclass("radiobtn_check");
                        } else {
                            chkimg.prop("checked", false).removeclass("radiobtn").removeclass("radiobtn_check").addclass("radiobtn");
                        }
                    } else if (this.options.selecttype == "checkbox") {
                        this._methods._checkednodes(chkimg, boolval);
                    };
                };
            },

            // @ method: setnodetext() 设置节点文本值
            // @ depict:设置树节点内容文本标题
            // @ params: nodecode     string  节点编码
            // @ params: nodetext   string  节点文本标题字符
            // @ pbtype: 外部调用方法
            setnodetext: function (nodecode, nodetext) {
                var txtnode = this.sdptree.find("#" + this.myfnid + "_sdptree_node_text_" + nodecode);
                if (txtnode.length > 0) {
                    if ($.isnull(nodetext)) { nodetext = ""; };
                    txtnode.text(nodetext);
                    if (nodecode == this.options.rootcode) {
                        this.options.roottext = nodetext;
                    } else {
                        this._methods._hsnodes[nodecode].nodetext = nodetext;
                    };
                };
            },

            // @ method: getnodechecked() 获取节点是否选中
            // @ depict:获取节点是否选中
            // @ params: [string] nodecode   节点编码
            // @ return: [bool]   ischecked  返回是否选中(布尔:true/false)
            // @ pbtype: 外部调用方法
            getnodechecked: function (nodecode) {
                var ischecked = false;
                var chkimg = this.sdptree.find("#" + this.myfnid + "_sdptree_node_chk_" + nodecode);
                if ((chkimg) && chkimg.length > 0) {
                    ischecked = chkimg.prop("checked");
                } else {
                    var tgnd = this.sdptree.find("#" + this.myfnid + "_sdptree_node_span_" + tgnodecode);
                    if ((tgnd) && tgnd.length > 0) {
                        ischecked = tgnd.hasclass("node_select");
                    }
                };
                return ischecked;
            },

            // @ method: getcheckednodes_array() 获取选中节点的数组 to array()
            // @ depict:获取树所有选中的节点 返回 array 数组 
            // @ return: array 数组  每项根式 item [
            // @                                     (1、nodecode 节点编码),  
            // @                                     (2、nodename 节点文本),
            // @                                     (3、nodesupcode 上级编码)
            // @                                     (4、nodelevel 节点级别)
            // @                                   ]
            // @ pbtype: 外部调用方法
            getcheckednodes_array: function () {
                var chknodelist = this.sdptree.find("span[stype='check']");
                var retarray = new array();
                var retcode = "", rettext = "", retsupcode = "", retlevel = -1; curicon = null;
                for (var tm1 = 0; tm1 < chknodelist.length; tm1++) {
                    curicon = $(chknodelist[tm1]);
                    if (!curicon.prop("checked")) { continue; };
                    retcode = curicon.attr("id").replace(this.myfnid + "_sdptree_node_chk_", "");
                    if (this.options.rootcode == retcode) { continue; };
                    rettext = curicon.parent().text();
                    retsupcode = this._methods._hsnodes[retcode].supnodecode;
                    retlevel = this._methods._hsnodes[retcode]._nodelevel;
                    retarray[retarray.length] = [retcode, rettext, retsupcode, retlevel];
                };
                return retarray;
            },

            // @ method: getcheckednodes_string() 获取选中节点的字符串
            // @ depict:获取树所有选中的节点 返回 string 字符串(拼接字符串) 
            // @ return:string 中的每项之间用小写的分号隔开
            // @         每项顺序:nodecode(节点编码),nodename(节点文本),nodesupcode(上级编码),nodelevel(节点级别);
            // @ pbtype: 外部调用方法
            getcheckednodes_string: function () {
                var chknodelist = this.sdptree.find("span[stype='check']");
                var retstring = [], curicon = null;
                var retcode = "", rettext = "", retsupcode = "", retlevel = "-1";
                for (var tm1 = 0; tm1 < chknodelist.length; tm1++) {
                    curicon = $(chknodelist[tm1]);
                    if (!curicon.prop("checked")) { continue; };
                    retcode = curicon.attr("id").replace(this.myfnid + "_sdptree_node_chk_", "");
                    if (this.options.rootcode == retcode) { continue; };
                    rettext = curicon.parent().text();
                    retsupcode = this._methods._hsnodes[retcode].supnodecode;
                    retlevel = this._methods._hsnodes[retcode]._nodelevel;
                    retstring.push(retcode + "," + rettext + "," + retsupcode + "," + retlevel + ";");
                };
                return retstring.join("");
            },

            // @ method: getcheckednodes_jsonobj() 获取选中节点的json数组
            // @ depict:获取树所有选中的节点   返回 json 对象数组 
            // @ return: json 对象数组
            // @         每项 item{ 
            // @                     nodecode: "节点编码",
            // @                     nodename: "节点文本", 
            // @                     supnodecode: "上级编码",
            // @                     nodelevel:节点级别
            // @                   }
            // @ pbtype: 外部调用方法
            getcheckednodes_jsonobj: function () {
                var chknodelist = this.sdptree.find("span[stype='check']");
                var retjson = new array();
                var retcode = "", rettext = "", retsupcode = "", retlevel = 0, curicon = null;
                for (var tm1 = 0; tm1 < chknodelist.length; tm1++) {
                    curicon = $(chknodelist[tm1]);
                    if (!curicon.prop("checked")) { continue; };
                    retcode = curicon.attr("id").replace(this.myfnid + "_sdptree_node_chk_", "");
                    if (this.options.rootcode == retcode) { continue; };
                    rettext = curicon.parent().text();
                    retsupcode = this._methods._hsnodes[retcode].supnodecode;
                    retlevel = this._methods._hsnodes[retcode]._nodelevel;
                    var newitem = {
                        nodecode: retcode,
                        nodetext: rettext,
                        supnodecode: retsupcode,
                        nodelevel: retlevel
                    };
                    retjson.push(newitem);
                };
                return retjson;
            },

            // @ method: getcheckednodes_xmlstr() 获取树所有选中的节点xml字符串
            // @ depict:获取树所有选中的节点生成固定格式的xml字符串 
            // @ return: xml字符串
            // @         每项 <row>
            // @                   <nodecode><![cdata[节点编码]]></nodecode>
            // @                   <nodetext><![cdata[节点文本]]></nodetext>
            // @                   <supnodecode><![cdata[上级编码]]></supnodecode>
            // @                   <nodelevel><![cdata[节点级别]]></nodelevel>
            // @               </row>
            // @ pbtype:  外部调用方法
            getcheckednodes_xmlstr: function () {
                var chknodelist = this.sdptree.find("span[stype='check']");
                var retxml = ["<root>"];
                var retcode = "", rettext = "", retsupcode = "", retlevel = 0, curicon = null;
                for (var tm1 = 0; tm1 < chknodelist.length; tm1++) {
                    curicon = $(chknodelist[tm1]);
                    if (!curicon.prop("checked")) { continue; };
                    retcode = curicon.attr("id").replace(this.myfnid + "_sdptree_node_chk_", "");
                    if (this.options.rootcode == retcode) { continue; };
                    rettext = curicon.parent().text();
                    retsupcode = this._methods._hsnodes[retcode].supnodecode;
                    retlevel = this._methods._hsnodes[retcode]._nodelevel;
                    retxml.push("<row><nodecode><![cdata[" + retcode + "]]></nodecode><nodetext><![cdata[" + rettext + "]]></nodetext><supnodecode><![cdata[" + retsupcode + "]]></supnodecode><nodelevel><![cdata[" + retlevel + "]]></nodelevel></row>");
                };
                retxml.push("</root>");
                return retxml.join("");
            },

            // @ method: getcheckednodes_hash() 获取树所有选中的节点hash数组
            // @ depict:获取树所有选中的节点 返回hash 数组 
            // @ return: hash 中的每项:hash.add(key=nodeid,value=nodetext);
            // @         item[key:nodeid] = value:nodetext
            // @         根据key: hash[key] 获取返回值:value
            // @ pbtype: 外部调用方法
            getcheckednodes_hash: function () {
                var chknodelist = this.sdptree.find("span[stype='check']");
                var rethash = $.hashtable();
                var retcode = "", rettext = "", curicon = null;
                for (var tm1 = 0; tm1 < chknodelist.length; tm1++) {
                    curicon = $(chknodelist[tm1]);
                    if (!curicon.prop("checked")) { continue; };
                    retcode = curicon.attr("id").replace(this.myfnid + "_sdptree_node_chk_", "");
                    if (this.options.rootcode == retcode) { continue; };
                    rettext = curicon.parent().text();
                    rethash.add(retcode, rettext);
                };
                return rethash;
            },

            // @ method: getallnodes_hash() 获取树所有节点hash数组
            // @ depict:获取树所有节点hash数组 返回hash 数组 
            // @ return: hash 中的每项:hash.add(key=nodeid,value=nodetext);
            // @         item[key:nodeid] = value:nodetext
            // @         根据key: hash[key] 获取返回值:value
            // @ pbtype:  外部调用方法
            getallnodes_hash: function () {
                return this._methods._hsnodes;
            },

            // @ method: getallnodes_array() 获取树所有节点array数组[分级的]
            // @ depict:获取树所有节点 返回 array 数组  
            // @ pbtype:  外部调用方法
            getallnodes_array: function () {
                return this._methods._dtnodes;
            },

            // @ method: expandnode() 展开所有节点
            // @ depict: 展开目录树的所有节点
            // @ pbtype: 外部调用方法
            expandall: function () {
                for (var tm0 = 0; tm0 < this._methods._dtnodes.length; tm0++) {
                    var tm_expnode = this._methods._dtnodes[tm0];
                    if (tm_expnode._havechild) {
                        this.expandnode(tm_expnode.nodecode);
                        this.expandallchilds(tm_expnode.nodecode);
                    };
                };
            },

            // @ method: expandallchilds() 展开指定节点的所有子节点
            // @ depict: 展开目录树的中执行节点下的所有子节点
            // @ params: nodecode  string 节点编码
            // @ pbtype: 外部调用方法
            expandallchilds: function (nodecode) {
                var tsnode = this._methods._hsnodes[nodecode];
                if (tsnode._havechild) {
                    for (var tm2 = 0; tm2 < tsnode._childs.length; tm2++) {
                        var subnode = tsnode._childs[tm2];
                        if (subnode._havechild) {
                            this.expandnode(subnode.nodecode);
                            this.expandallchilds(subnode.nodecode);
                        };
                    };
                };
            },

            // @ method: expandnode() 展开指定的节点
            // @ depict: 根据节点编码 执行展开此节点
            // @ params: nodecode  string 节点编码
            // @ pbtype: 外部调用方法
            expandnode: function (nodecode) {
                var $plusimg = this.sdptree.find("#" + this.myfnid + "_sdptree_node_plus_" + nodecode);
                var $clipdiv = this.sdptree.find("#" + this.myfnid + "_sdptree_node_clip_" + nodecode);
                var $nodeicn = this.sdptree.find("#" + this.myfnid + "_sdptree_node_icon_" + nodecode);
                if ($plusimg.length > 0) {
                    if ($plusimg.hasclass("node_plug_0n")) {
                        if (!$plusimg.hasclass("node_expd_0n")) { $plusimg.addclass("node_expd_0n").prop("open", true); };
                    } else if ($plusimg.hasclass("node_plug_1l")) {
                        if (!$plusimg.hasclass("node_expd_1l")) { $plusimg.addclass("node_expd_1l").prop("open", true); };
                    } else if ($plusimg.hasclass("node_plug_2b")) {
                        if (!$plusimg.hasclass("node_expd_2b")) { $plusimg.addclass("node_expd_2b").prop("open", true); };
                    } else if ($plusimg.hasclass("node_plug_2t")) {
                        if (!$plusimg.hasclass("node_expd_2t")) { $plusimg.addclass("node_expd_2t").prop("open", true); };
                    } else if ($plusimg.hasclass("node_plug_3a")) {
                        if (!$plusimg.hasclass("node_expd_3a")) { $plusimg.addclass("node_expd_3a").prop("open", true); };
                    };
                };

                if ($clipdiv.length > 0) { $clipdiv.css("display", "block"); };
                if ($nodeicn.length > 0) {
                    if ($nodeicn.hasclass("custom_img")) {
                        var icnbgimg = ($nodeicn.attr("expdimg")) ? $nodeicn.attr("expdimg") : $nodeicn.attr("collimg");
                        $nodeicn.css("background-image", "url(" + icnbgimg + ")");
                    } else {
                        if (($nodeicn.hasclass("folder_collapse")) && (!$nodeicn.hasclass("folder_expand"))) { $nodeicn.addclass("folder_expand"); };
                    }
                };
            },

            // @ method: collapseall() 收缩所有节点
            // @ depict: 收缩目录树的所有节点
            // @ pbtype: 外部调用方法
            collapseall: function () {
                for (var tm0 = 0; tm0 < this._methods._dtnodes.length; tm0++) {
                    var tm_collnode = this._methods._dtnodes[tm0];
                    if (tm_collnode._havechild) {
                        this.collapsenode(tm_collnode.nodecode);
                        this.collapseallchilds(tm_collnode.nodecode);
                    };
                };
            },

            // @ method: collapseallchilds() 收缩指定节点的所有子节点
            // @ depict: 收缩目录树的中执行节点下的所有子节点
            // @ params: nodecode  string 节点编码
            // @ pbtype: 外部调用方法
            collapseallchilds: function (nodecode) {
                var tsnode = this._methods._hsnodes[nodecode];
                if (tsnode._havechild) {
                    for (var tm2 = 0; tm2 < tsnode._childs.length; tm2++) {
                        var subnode = tsnode._childs[tm2];
                        if (subnode._havechild) {
                            this.collapsenode(subnode.nodecode);
                            this.collapseallchilds(subnode.nodecode);
                        };
                    };
                };
            },

            // @ method: collapsenode() 收缩指定的节点
            // @ depict: 根据节点编码收缩此节点 
            // @ params: nodecode  string 节点编码
            // @ pbtype: 外部调用方法
            collapsenode: function (nodecode) {
                var $plusimg = this.sdptree.find("#" + this.myfnid + "_sdptree_node_plus_" + nodecode);
                var $clipdiv = this.sdptree.find("#" + this.myfnid + "_sdptree_node_clip_" + nodecode);
                var $nodeicn = this.sdptree.find("#" + this.myfnid + "_sdptree_node_icon_" + nodecode);
                if ($plusimg.length > 0) {
                    if ($plusimg.hasclass("node_plug_0n")) {
                        if ($plusimg.hasclass("node_expd_0n")) { $plusimg.removeclass("node_expd_0n").prop("open", false); };
                    } else if ($plusimg.hasclass("node_plug_1l")) {
                        if ($plusimg.hasclass("node_expd_1l")) { $plusimg.removeclass("node_expd_1l").prop("open", false); };
                    } else if ($plusimg.hasclass("node_plug_2b")) {
                        if ($plusimg.hasclass("node_expd_2b")) { $plusimg.removeclass("node_expd_2b").prop("open", false); };
                    } else if ($plusimg.hasclass("node_plug_2t")) {
                        if ($plusimg.hasclass("node_expd_2t")) { $plusimg.removeclass("node_expd_2t").prop("open", false); };
                    } else if ($plusimg.hasclass("node_plug_3a")) {
                        if ($plusimg.hasclass("node_expd_3a")) { $plusimg.removeclass("node_expd_3a").prop("open", false); };
                    };
                };
                if ($clipdiv.length > 0) { $clipdiv.css("display", "none"); };
                if ($nodeicn.length > 0) {
                    if ($nodeicn.hasclass("custom_img")) {
                        var icnbgimg = ($nodeicn.attr("collimg")) ? $nodeicn.attr("collimg") : $nodeicn.attr("expdimg");
                        $nodeicn.css("background-image", "url(" + icnbgimg + ")");
                    } else {
                        if (($nodeicn.hasclass("folder_collapse")) && ($nodeicn.hasclass("folder_expand"))) {
                            $nodeicn.removeclass("folder_expand");
                        }
                    }
                };
            },

            // @ method: expandlevel() 展开目录树中某层次所有节点 
            // @ depict: 根据节点层次级别
            // @ params: levelnum  [number]  节点层次级别[注意级别是从1开始,根目录属于0级]
            // @ pbtype: 外部调用方法
            expandlevel: function (levelnum) {
                levelnum = parseint(levelnum, 10);
                if (isnan(levelnum)) { return; };
                var _treenodeshash = this._methods._hsnodes;
                for (var ll = 1; ll <= levelnum; ll++) {
                    for (var ndcode in _treenodeshash) {
                        if (_treenodeshash.hasownproperty(ndcode)) {
                            var nditem = _treenodeshash[ndcode];
                            if (nditem._nodelevel == ll) {
                                this.expandnode(nditem.nodecode);
                            }
                        }
                    };
                };
            },

            // @ method: collapselevel() 收缩目录树中某层次所有节点 
            // @ depict: 根据节点层次级别
            // @ params: levelnum  [number]  节点层次级别[注意级别是从1开始,根目录属于0级]
            // @ pbtype: 外部调用方法
            collapselevel: function (levelnum) {
                levelnum = parseint(levelnum, 10);
                if (isnan(levelnum)) { return; };

                var _treenodeshash = this._methods._hsnodes;
                for (var ndcode in _treenodeshash) {
                    if (_treenodeshash.hasownproperty(ndcode)) {
                        var nditem = _treenodeshash[ndcode];
                        if (nditem._nodelevel == levelnum) {
                            this.collapsenode(nditem.nodecode); // 收缩指定的节点
                        }
                    }
                };
            },

            // @ method: getobject() 获取控件jquery 对象
            // @ depict: 获取插件所对应的dom 控件 jquery 对象
            // @ return: [object]  返回控件jquery 对象 空为null
            // @ pbtype: 外部调用方法
            getobject: function () {
                return this.myobject;
            },

            // @ method: getid() 获取控件id
            // @ depict: 获取此插件对应的控件id属性值
            // @ return: [string] 控件id
            // @ pbtype: 外部调用方法
            getid: function () {
                var _thisid = null;
                if (this.myobject != null) { _thisid = this.myobject.attr("id"); };
                if ($.isnull(_thisid) == true) { _thisid = null; };
                return _thisid;
            },

            // @ method: getsdpid() 获取控件内嵌 id
            // @ depict: 获取此插件对应的控件sdp id属性值
            // @ pbtype: 外部调用方法
            getsdpid: function () {
                var _thissdpid = null;
                if (this.myobject != null) { _thissdpid = this.myobject.attr("sdpid"); };
                if ($.isnull(_thissdpid) == true) { _thissdpid = null; };
                return _thissdpid;
            },

            // @ method: onlocked() 锁定控件
            // @ depict: 执行控件的锁定
            // @ pbtype: 外部调用方法
            onlocked: function () {
                if (this.myobject == null) { return; };
                if (this.getlocked() == false) {
                    this.myobject.attr("sdplocked", "yes");
                }
            },

            // @ method: onunlock() 解锁控件
            // @ depict: 执行控件的锁定
            // @ pbtype: 外部调用方法
            onunlock: function () {
                if (this.myobject == null) { return; };
                if (this.getlocked() == true) {
                    this.myobject.attr("sdplocked", "no");
                }
            },

            // @ method: getlocked() 获取控件是否锁定
            // @ depict: 获取控件的锁定状态
            // @ return: [bool] 控件锁定状态 true false
            // @ pbtype: 外部调用方法
            getlocked: function () {
                if (this.myobject) {
                    return (this.myobject.attr("sdplocked") == "yes");
                } else {
                    return false;
                }
            },

            // @ method: getvisible() 获取控件是否可见
            // @ depict: 获取控件的可见状态(显示/隐藏)
            // @ return: [bool] 控件锁定状态 true: 表示显示(可见); false:表示隐藏(不可见)
            // @ pbtype: 外部调用方法
            getvisible: function () {
                if (this.myobject != null) {
                    return this.myobject.is(":hidden");
                } else {
                    return true;
                }
            },

            // @ method: onrefresh() 树刷新
            // @ depict: 目录树刷新[当前树是通过自动加载的时,即从sql中获取有效]
            // @ pbtype: 外部调用方法
            onrefresh: function () {
                var p = this.options;
                this.focusnodecode = "";
            },

            // @ method: _loadparam() 加载控件option参数
            // @ depict: 加载控件在设计器中option参数
            // @ pbtype: 内部调用方法
            _loadparam: function () {
                this.options = $.extend({}, this.defaults);  // 合并参数
            },

            // @ method: _bindevent() 事件绑定
            // @ depict: 执行控件 样式、事件等绑定
            // @ pbtype: 内部调用方法
            _bindevent: function () {
                if (!this.mycontainer) { return; };
                var _this = this;
                this.mycontainer.click(function (event) {
                    _this._onclickhandle(event);
                }).dblclick(function (event) {
                    _this._ondblclickhandle(event);
                }).contextmenu(function (event) {
                    return false;
                });
            },

            // @ method: _onclickhandle() 节点单击事件处理
            // @ depict: 对目录树节点的单击事件处理
            // @ params: [object] event 当前目标对象(dom)
            // @ pbtype: 内部调用方法
            _onclickhandle: function (event) {
                var e = window.event || event;
                e = e.srcelement || e.target;
                if (e.tagname.tolowercase() != "span") { return; };
                var tgobj = $(e);
                var tgnodecode = null, tgnd = null;
                switch (tgobj.attr("stype")) {
                    case "text":
                        tgnodecode = tgobj.attr("id").replace(this.myfnid + "_sdptree_node_text_", "");
                        tgnd = this.sdptree.find("#" + this.myfnid + "_sdptree_node_span_" + tgnodecode);
                        if (!tgnd.hasclass("node_select")) {
                            tgnd.addclass("node_select");
                            var forfocus = this.sdptree.find("#" + this.myfnid + "_sdptree_node_span_" + this.focusnodecode);
                            if (forfocus.length > 0) { forfocus.removeclass("node_select"); };
                            this.focusnodecode = tgnodecode;
                        };
                        this._onnodeclick(tgnd);
                        break;
                    case "plus":
                        tgnodecode = tgobj.attr("id").replace(this.myfnid + "_sdptree_node_plus_", "");
                        if (typeof (tgobj.prop("open")) == "undefined") {
                            if (tgobj.hasclass("node_plug_0n")) {
                                if (tgobj.hasclass("node_expd_0n")) { tgobj.prop("open", true); } else { tgobj.prop("open", false); };
                            } else if (tgobj.hasclass("node_plug_1l")) {
                                if (tgobj.hasclass("node_expd_1l")) { tgobj.prop("open", true); } else { tgobj.prop("open", false); };
                            } else if (tgobj.hasclass("node_plug_2b")) {
                                if (tgobj.hasclass("node_expd_2b")) { tgobj.prop("open", true); } else { tgobj.prop("open", false); };
                            } else if (tgobj.hasclass("node_plug_2t")) {
                                if (tgobj.hasclass("node_expd_2t")) { tgobj.prop("open", true); } else { tgobj.prop("open", false); };
                            } else if (tgobj.hasclass("node_plug_3a")) {
                                if (tgobj.hasclass("node_expd_3a")) { tgobj.prop("open", true); } else { tgobj.prop("open", false); };
                            };
                        };
                        if (tgobj.prop("open")) { this.collapsenode(tgnodecode); } else { this.expandnode(tgnodecode); };
                        break;
                    case "check":
                        if (this.getlocked() == true) { return; };
                        tgnodecode = tgobj.attr("id").replace(this.myfnid + "_sdptree_node_chk_", "");
                        tgnd = this.sdptree.find("#" + this.myfnid + "_sdptree_node_span_" + tgnodecode);
                        var _oldcheckstate = tgobj.prop("checked") || false;
                        this.setnodechecked(tgnodecode, !tgobj.prop("checked"));
                        var _newcheckstate = tgobj.prop("checked") || false;
                        if (_oldcheckstate != _newcheckstate) { this._onnodecheckedchange(tgnd); };
                        break;
                };
            },

            // @ method: _ondblclickhandle() 节点双击事件处理
            // @ depict: 对目录树节点的双击事件处理
            // @ params: [object] event 当前目标对象(dom)
            // @ pbtype: 内部调用方法
            _ondblclickhandle: function (event) { // 节点双击事件
                var e = event || window.event;
                e = e.srcelement || e.target;
                if (e.tagname.tolowercase() != "span") { return; };
                var dblobj = $(e);
                if (dblobj.attr("stype") == "text") {
                    var dblnodecode = dblobj.attr("id").replace(this.myfnid + "_sdptree_node_text_", "");
                    var plusobj = this.sdptree.find("#" + this.myfnid + "_sdptree_node_plus_" + dblnodecode);
                    var tgnd = this.sdptree.find("#" + this.myfnid + "_sdptree_node_span_" + dblnodecode);
                    if (plusobj.length > 0) {
                        if (typeof (plusobj.prop("open")) == "undefined") {
                            if (plusobj.hasclass("node_plug_0n")) {
                                if (plusobj.hasclass("node_expd_0n")) { plusobj.prop("open", true); } else { plusobj.prop("open", false); };
                            } else if (plusobj.hasclass("node_plug_1l")) {
                                if (plusobj.hasclass("node_expd_1l")) { plusobj.prop("open", true); } else { plusobj.prop("open", false); };
                            } else if (plusobj.hasclass("node_plug_2b")) {
                                if (plusobj.hasclass("node_expd_2b")) { plusobj.prop("open", true); } else { plusobj.prop("open", false); };
                            } else if (plusobj.hasclass("node_plug_2t")) {
                                if (plusobj.hasclass("node_expd_2t")) { plusobj.prop("open", true); } else { plusobj.prop("open", false); };
                            } else if (plusobj.hasclass("node_plug_3a")) {
                                if (plusobj.hasclass("node_expd_3a")) { plusobj.prop("open", true); } else { plusobj.prop("open", false); };
                            };
                        };
                        if (plusobj.prop("open")) {
                            this.collapsenode(dblnodecode);
                        }
                        else { this.expandnode(dblnodecode); };
                    };
                    this._onnodedblclick(tgnd);
                };
            },

            // @ method: _onnodeclick() 执行节点自定单击事件
            // @ depict: 执行节点自定单击事件
            // @ params: [object] node 树节点dom对象 
            // @ pbtype: 内部调用方法
            _onnodeclick: function (node) {
                if (!node) { return; };
                var nodeclickevent = this.options.nodeclick;
                if (typeof (nodeclickevent) != 'function') { nodeclickevent = $.strtofunction(nodeclickevent); };
                if (typeof (nodeclickevent) == 'function') {
                    try {
                        var ndcode = $(node).attr("id").replace(this.myfnid + "_sdptree_node_span_", "");
                        var nditem = new this.nodeitem();
                        if (ndcode == this.options.rootcode) {
                            nditem.nodecode = this.options.rootcode;
                            nditem.nodetext = this.options.roottext;
                            nditem.nodeurl = this.options.rooturl;
                            nditem.iconcollapse = this.options.rooticon;
                        } else {
                            nditem = this._methods._hsnodes[ndcode];
                        };

                        var eparams = {
                            treeplug: this,
                            nodeobject: $(node)[0],
                            nodeparams: nditem
                        };
                        nodeclickevent.call(null, eparams);
                    } catch (error) {
                        alert("控件单击事件执行错误!" + error);
                    }
                };
            },

            // @ method: _onnodedblclick() 执行节点自定双击事件
            // @ depict: 执行节点自定双击事件
            // @ params: [object] node 树节点dom对象
            // @ pbtype: 内部调用方法
            _onnodedblclick: function (node) {
                if (!node) { return; };
                var nodedblclickevent = this.options.nodedblclick;
                if (typeof (nodedblclickevent) != 'function') { nodedblclickevent = $.strtofunction(nodedblclickevent); };
                if (typeof (nodedblclickevent) == 'function') {
                    try {
                        var ndcode = $(node).attr("id").replace(this.myfnid + "_sdptree_node_span_", "");
                        var nditem = new this.nodeitem();
                        if (ndcode == this.options.rootcode) {
                            nditem.nodecode = this.options.rootcode;
                            nditem.nodetext = this.options.roottext;
                            nditem.nodeurl = this.options.rooturl;
                            nditem.iconcollapse = this.options.rooticon;
                        } else {
                            nditem = this._methods._hsnodes[ndcode];
                        };
                        var eparams = {
                            treeplug: this,
                            nodeobject: $(node)[0],
                            nodeparams: nditem
                        };
                        nodedblclickevent.call(null, eparams);
                    } catch (error) {
                        alert("控件双击事件执行错误!" + error);
                    }
                };
            },

            // @ method: _onnodecheckedchange() 执行节点自定选择(选中状态)改变事件
            // @ depict: 执行节点自定选择(选中状态)改变事件
            // @ params: [object] node 树节点dom对象
            // @ pbtype: 内部调用方法
            _onnodecheckedchange: function (node) {
                if (!node) { return; };
                var nodecheckedchange = this.options.checkedchange;
                if (typeof (nodecheckedchange) != 'function') { nodecheckedchange = $.strtofunction(nodecheckedchange); };
                if (typeof (nodecheckedchange) == 'function') {
                    try {
                        var ndcode = $(node).attr("id").replace(this.myfnid + "_sdptree_node_span_", "");
                        var nditem = new this.nodeitem();
                        if (ndcode == this.options.rootcode) {
                            nditem.nodecode = this.options.rootcode;
                            nditem.nodetext = this.options.roottext;
                            nditem.nodeurl = this.options.rooturl;
                            nditem.iconcollapse = this.options.rooticon;
                        } else {
                            nditem = this._methods._hsnodes[ndcode];
                        };
                        var eparams = {
                            treeplug: this,
                            nodeobject: $(node)[0],
                            nodeparams: nditem
                        };
                        nodecheckedchange.call(null, eparams);
                    } catch (error) {
                        alert("控件双击事件执行错误!" + error);
                    }
                };
            },

            _methods: {
                _fnobject: null,
                _myobject: null,
                _mycontainer: null,
                _myfnid: "",
                _sdptree: null,
                _mynodes: [],
                _hsnodes: null,
                _dtnodes: null,
                _createtree: function () {    // 创建树html对象
                    // 初始化变量参数
                    this._sdptree.empty();       // 清空目录树内的所有内容
                    this._fnobject.focusnodecode = "";
                    this._mynodes = [];
                    this._hsnodes = new $.hashtable();
                    this._dtnodes = [];
                    var _tmnodes = [], f = this._fnobject, p = this._fnobject.options, _this = this;

                    // 重组目录节点(依次将所有的节点组成自己的树) 一次循环完成 提高效率
                    function renew_groupnodes(currnodes) {
                        // 重绘节点上下级关系
                        function renew_tree(renode) {
                            if (_tmnodes[renode.nodecode]) {
                                for (var n = 0; n < _tmnodes[renode.nodecode].length; n++) {
                                    renode._childs[n] = _tmnodes[renode.nodecode][n];
                                    renode._childs[n]._parent = renode;
                                    renode._childs[n]._firstflag = (n == 0) ? true : false;
                                    renode._childs[n]._lastflag = (n == (_tmnodes[renode.nodecode].length - 1)) ? true : false;
                                    renode._childs[n]._havechild = (_tmnodes[_tmnodes[renode.nodecode][n].nodecode]) ? true : false;
                                    renode._childs[n]._nodelevel = renode._nodelevel + 1;
                                    renew_tree(_tmnodes[renode.nodecode][n]);  // 迭代循环
                                }
                            }
                        };

                        var m = 0;
                        _tmnodes[p.rootcode] = [];   // 根节点
                        for (m = 0; m < currnodes.length; m++) {
                            var _nd = currnodes[m];
                            _tmnodes[_nd.supnodecode] = _tmnodes[_nd.supnodecode] || [];
                            _tmnodes[_nd.supnodecode].push(_nd);
                            _this._hsnodes.add(_nd.nodecode, _nd);
                        };
                        var _rtnodes = _tmnodes[p.rootcode];

                        for (m = 0; m < _rtnodes.length; m++) {
                            _this._dtnodes[m] = _rtnodes[m];
                            _this._dtnodes[m]._parent = null;
                            _this._dtnodes[m]._firstflag = (m == 0) ? true : false;  // 设置参数
                            _this._dtnodes[m]._lastflag = (m == (_rtnodes.length - 1)) ? true : false;
                            _this._dtnodes[m]._havechild = (_tmnodes[_rtnodes[m].nodecode]) ? true : false;
                            _this._dtnodes[m]._nodelevel = 1;
                            renew_tree(_rtnodes[m]);                               // 迭代循环
                        };

                        _rtnodes = null;
                        _tmnodes = null;
                    };

                    // 执行节点重组
                    renew_groupnodes(f.curnodes);
                    f.curnodes = [];  // 清空临时节点数组变量,便于后续重新加载使用

                    // 定义前缀字符
                    var full_prefix = this._myfnid + "_sdptree_node_full";     // 完整的一个节点div(包含:连线、+号图片、节点图片、选择框、节点文本)
                    var node_prefix = this._myfnid + "_sdptree_node_span";     // 节点span
                    // var plus_prefix = this._myfnid + "_sdptree_node_plus";     // + 号图片
                    var nimg_prefix = this._myfnid + "_sdptree_node_icon";     // 节点图片
                    var chkr_prefix = this._myfnid + "_sdptree_node_chk";      // 选择图片
                    var text_prefix = this._myfnid + "_sdptree_node_text";     // 节点文本
                    var clip_prefix = this._myfnid + "_sdptree_node_clip";     // 子节点div

                    // 注意点:前台传入的所有自定义的图标,全部已经是指定的完整路径了,所以这里就不需要转换
                    var _rootcode = p.rootcode;
                    if (p.showroot) {           // 判定是否显示根节点
                        var tmrhtml = [];
                        tmrhtml.push('<div id="' + full_prefix + '_' + _rootcode + '" stype="full" >');
                        tmrhtml.push('<span id="' + node_prefix + '_' + _rootcode + '" class="node_default" stype="node" >');
                        if (p.showicon) {
                            tmrhtml.push('<span id="' + nimg_prefix + '_' + _rootcode + '" stype="icon" ');
                            if (p.rooticon) {   // 是否客户自定义的图片
                                tmrhtml.push('class="custom_img" style="background-image: url(' + (p.rooticon) + ');"');
                            } else {                                // 启用默认的样式图片
                                tmrhtml.push('class="root_img"');
                            };
                            tmrhtml.push(' ></span>');
                        };
                        if (p.selecttype == "checkbox") {     // 是否开启选择按钮
                            tmrhtml.push('<span id="' + chkr_prefix + '_' + _rootcode + '" stype="check" class="checkbox"></span>');
                        } else if (p.selecttype == "radio") {
                            tmrhtml.push('<span id="' + chkr_prefix + '_' + _rootcode + '" stype="check" class="radiobtn"></span>');
                        };
                        tmrhtml.push('<span id="' + text_prefix + '_' + _rootcode + '"  class="root_title" stype="text">' + p.roottext + '</span>');
                        tmrhtml.push('</span>');
                        tmrhtml.push('</div>');
                        this._sdptree.append($(tmrhtml.join("")));
                        tmrhtml = null;
                    };
                    var $clipdom = null;
                    if (p.showroot) $clipdom = $('<div id="' + clip_prefix + '_' + _rootcode + '" class="clipdiv" stype="clip" style="display: block" ></div>');
                    var _rechtml = this._createnodes(this._dtnodes);
                    if (_rechtml) {
                        if ($clipdom) { $clipdom.append($(_rechtml)); this._sdptree.append($clipdom); } else { this._sdptree.append($(_rechtml)); };
                    } else {
                        if ($clipdom) { this._sdptree.append($clipdom); };
                    };
                    _rechtml = null;

                    // 绑定事件
                    this._bindevent();
                    if (p.openall) { f.expandall(); };
                },
                _createnodes: function (crnodes) { // 创建节点html
                    var full_prefix = this._myfnid + "_sdptree_node_full";     // 完整的一个节点div(包含:连线、+号图片、节点图片、选择框、节点文本)
                    var node_prefix = this._myfnid + "_sdptree_node_span";     // 节点span
                    var plus_prefix = this._myfnid + "_sdptree_node_plus";     // + 号图片
                    var nimg_prefix = this._myfnid + "_sdptree_node_icon";     // 节点图片
                    var chkr_prefix = this._myfnid + "_sdptree_node_chk";      // 选择图片
                    var text_prefix = this._myfnid + "_sdptree_node_text";     // 节点文本
                    var clip_prefix = this._myfnid + "_sdptree_node_clip";     // 子节点div
                    var p = this._fnobject.options;                            // 参数变量

                    var tmhtml = [];
                    for (var m = 0; m < crnodes.length; m++) {
                        var crnode = crnodes[m];
                        tmhtml.push('<div id="' + full_prefix + '_' + crnode.nodecode + '" stype="full" >');
                        var tmindent = [];
                        var tmparent = crnode._parent;
                        var lv = crnode._nodelevel;
                        while (lv > 1) { tmindent[tmindent.length] = tmparent; tmparent = tmparent._parent; lv--; };
                        for (lv = tmindent.length - 1; lv >= 0; lv--) {
                            tmhtml.push('<span class="' + ((this._fnobject.options.showline == true) ? ((tmindent[lv]._lastflag == false) ? "node_line_10" : "nullimg") : "nullimg") + '" stype="line" ></span>');
                        };
                        tmindent = null;
                        tmparent = null;
                        var tmndcode = crnode.nodecode;
                        if (p.showline == true) {          // 2、节点自身图标 + - 
                            if (crnode._havechild) {
                                if (crnode._nodelevel == 1 && p.showroot == false && crnode._firstflag == true) {
                                    tmhtml.push('<span id="' + plus_prefix + '_' + tmndcode + '"  stype="plus" class="' + ((crnode._lastflag) ? "node_plug_1l" : "node_plug_2b") + '"></span>');
                                } else {
                                    tmhtml.push('<span id="' + plus_prefix + '_' + tmndcode + '"  stype="plus" class="' + ((crnode._lastflag) ? "node_plug_2t" : "node_plug_3a") + '"></span>');
                                };
                            } else {
                                if (crnode._nodelevel == 1 && p.showroot == false && crnode._firstflag == true) {
                                    tmhtml.push('<span class="' + ((crnode._lastflag) ? "node_line_11" : "node_line_20") + '" stype="line" ></span>');
                                } else {
                                    tmhtml.push('<span class="' + ((crnode._lastflag) ? "node_line_21" : "node_line_3n") + '" stype="line" ></span>');
                                };
                            };

                        } else {   // 不显示线
                            var tmplusstr = "stype=\"plus\" id=" + plus_prefix + "_" + tmndcode;
                            var tmlinestr = "stype=\"line\"";
                            tmhtml.push('<span class="' + ((crnode._havechild == true) ? "node_plug_0n" : "nullimg") + '" ' + ((crnode._havechild == true) ? tmplusstr : tmlinestr) + ' ></span>');
                        };
                        tmhtml.push('<span id="' + node_prefix + '_' + tmndcode + '" class="node_default" stype="node" >');  // 3、添加节点相关

                        // 节点小图标
                        if (p.showicon) {

                            // 节点图标  根据每个节点自身是否定义 如果没有定义,再从options 参数中查询
                            var cur_collapseicon = ""; //                    iconexpand: "",  iconcollapse: ""
                            var cur_expandicon = "";
                            if ($.isnull(crnode.iconcollapse) == false) {  // 判定节点收缩时显示的图标
                                cur_collapseicon = crnode.iconcollapse;    // 默认显示图标[收缩]
                                cur_expandicon = crnode.iconexpand;        // 展开显示图标[展开]
                            } else {
                                if (crnode._havechild == true)             // 判定是否有子节点
                                {
                                    if ($.isnull(p.middefticon) == false) {
                                        cur_collapseicon = p.middefticon;   // 中间节点收缩[整体自定]
                                        cur_expandicon = p.midexpdicon;     // 中间节点展开[整体自定]
                                    }
                                } else {
                                    if ($.isnull(p.endnodeicon) == false) {
                                        cur_collapseicon = p.endnodeicon;   // 末级节点[整体自定]
                                        cur_expandicon = "";
                                    }
                                }
                            };

                            // 节点图片  
                            if ($.isnull(cur_collapseicon) == false) {
                                tmhtml.push('<span class="custom_img" id="' + nimg_prefix + '_' + tmndcode + '" stype="icon" collimg="' + cur_collapseicon + '" expdimg="' + cur_expandicon + '" style="background-image: url(' + cur_collapseicon + ');"></span>');
                            } else {
                                tmhtml.push('<span class="' + ((crnode._havechild == true) ? "folder_collapse" : "folder_last") + '" id="' + nimg_prefix + '_' + tmndcode + '" stype="icon"></span>');
                            };
                        };
                        if (p.selecttype == "checkbox") {   // 允许添加选择按钮
                            tmhtml.push('<span id="' + chkr_prefix + '_' + tmndcode + '" stype="check" class="checkbox" ></span>');
                        } else if (p.selecttype == "radio") {
                            tmhtml.push('<span id="' + chkr_prefix + '_' + tmndcode + '" stype="check" class="radiobtn" ></span>');
                        };
                        tmhtml.push('<span id="' + text_prefix + '_' + tmndcode + '" class="node_title" stype="text">' + crnode.nodetext + '</span>');      //  节点名称
                        tmhtml.push('</span>');
                        tmhtml.push('</div>');
                        if (crnode._childs.length > 0) {
                            tmhtml.push('<div id="' + clip_prefix + '_' + tmndcode + '" class="clipdiv" stype="clip"  style="display:none;" >');  // 第一级以下全部隐藏
                            tmhtml.push(this._createnodes(crnode._childs));
                            tmhtml.push('</div>');
                        };
                    };
                    return tmhtml.join("");
                },
                _updatenode: function (nodecode) {            //  更新节点显示样式
                    var tmnownode = this._hsnodes[nodecode];  //  当前节点的node数据
                    if (!tmnownode) { return; };

                    // 1、首先更新自己
                    var nowfullnode = $(this._fnobject.getnode(nodecode));                                       // 完整的节点对象
                    var nowspannode = nowfullnode.find("#" + this._myfnid + "_sdptree_node_span_" + nodecode);   // 节点nodespan
                    var nowplusspan = nowspannode.prev();                                                        // 节点plus + - 图标
                    var nowiconspan = nowfullnode.find("#" + this._myfnid + "_sdptree_node_icon_" + nodecode);   // 节点icon 图标

                    var tmindent = null, tmparent = null, lv = null, lineclass = "", tmi = 0;
                    if (!tmnownode._havechild) {  // 无子节点
                        // (1)、更新plus
                        nowplusspan.removeattr("id").removeattr("open").attr("stype", "line");
                        if (this._fnobject.options.showline == true) {  // 显示连接线
                            var lineclassname = "";
                            if (tmnownode._nodelevel == 1 && this._fnobject.options.showroot == false && tmnownode._firstflag == true) {
                                lineclassname = (tmnownode._lastflag) ? "node_line_11" : "node_line_20";
                            } else {
                                lineclassname = (tmnownode._lastflag) ? "node_line_21" : "node_line_3n";
                            };
                            nowplusspan.attr("class", lineclassname); // 更新样式classname
                        } else {  // 不显示连接线
                            nowplusspan.attr("class", "nullimg");
                        };
                        // (2)、更新icon
                        if (nowiconspan.length > 0) {
                            if (!nowiconspan.hasclass("custom_img")) { nowiconspan.attr("class", "folder_last"); };
                        };

                        // (3)、更新line
                        tmindent = [];
                        tmparent = tmnownode._parent;
                        lv = tmnownode._nodelevel;
                        while (lv > 1) { tmindent[tmindent.length] = tmparent; tmparent = tmparent._parent; lv--; };
                        lineclass = "", tmi = 0;
                        for (lv = tmindent.length - 1; lv >= 0; lv--) {
                            lineclass = ((this._fnobject.options.showline == true) ? ((tmindent[lv]._lastflag == false) ? "node_line_10" : "nullimg") : "nullimg");
                            $(nowfullnode[0].childnodes[tmi]).attr("class", lineclass);
                            tmi++;
                        };

                        tmindent = null;
                        tmparent = null;
                        lineclass = null;
                    } else {    // 有子节点
                        // (1)、更新plus
                        var nowclipdiv = this._sdptree.find("#" + this._myfnid + "_sdptree_node_clip_" + nodecode);
                        var isopen = (nowclipdiv.css("display") == "none") ? false : true;
                        nowplusspan.attr("id", this._myfnid + "_sdptree_node_plus_" + nodecode).attr("stype", "plus");
                        if (isopen) { nowplusspan.attr("open", true); } else { nowplusspan.attr("open", false); };  // 设置展开状态
                        if (this._fnobject.options.showline == true) {  // 显示连接线
                            var plusclassname = "";
                            if (tmnownode._nodelevel == 1 && this._fnobject.options.showroot == false && tmnownode._firstflag == true) {
                                plusclassname = (tmnownode._lastflag) ? "node_plug_1l" : "node_plug_2b";
                            } else { plusclassname = (tmnownode._lastflag) ? "node_plug_2t" : "node_plug_3a"; };
                            nowplusspan.attr("class", plusclassname);               // 设置plus 收缩样式
                            if (isopen) {
                                switch (plusclassname) {
                                    case "node_plug_1l":
                                        nowplusspan.addclass("node_expd_1l");
                                        break;
                                    case "node_plug_2b":
                                        nowplusspan.addclass("node_expd_2b");
                                        break;
                                    case "node_plug_2t":
                                        nowplusspan.addclass("node_expd_2t");
                                        break;
                                    case "node_plug_3a":
                                        nowplusspan.addclass("node_expd_3a");
                                        break;
                                };
                            };
                        } else {  // 不显示连接线
                            nowplusspan.attr("class", "node_plug_0n");              // 设置plus 收缩样式
                            if (isopen) nowplusspan.addclass("node_expd_0n");       // 添加plus 展开样式
                        };

                        // (2)、更新icon
                        if (nowiconspan.length > 0) {
                            if (!nowiconspan.hasclass("custom_img")) {
                                nowiconspan.attr("class", "folder_collapse");            // 设置icon 收缩样式 
                                if (isopen) {                                            // 添加icon 展开样式
                                    nowiconspan.addclass("folder_expand");
                                };
                            };
                        };

                        // (3)、更新line
                        tmindent = [];
                        tmparent = tmnownode._parent;
                        lv = tmnownode._nodelevel;
                        while (lv > 1) { tmindent[tmindent.length] = tmparent; tmparent = tmparent._parent; lv--; };
                        lineclass = "", tmi = 0;
                        for (lv = tmindent.length - 1; lv >= 0; lv--) {
                            lineclass = ((this._fnobject.options.showline == true) ? ((tmindent[lv]._lastflag == false) ? "node_line_10" : "nullimg") : "nullimg");
                            $(nowfullnode[0].childnodes[tmi]).attr("class", lineclass);
                            tmi++;
                        };

                        tmindent = null;
                        tmparent = null;
                        lineclass = null;
                    };

                    // 2、其次更新下级
                    if (tmnownode._havechild) {
                        for (var tm2 = 0; tm2 < tmnownode._childs.length; tm2++) {
                            var tmsubnodecode = tmnownode._childs[tm2].nodecode;
                            this._updatenode(tmsubnodecode); // 迭代循环更新子节点
                        };
                    };
                },

                // @ params: [bool]   isopall   是否全部 说明:前面调用时候,根据情况 是否执行全部节点的标志(一般使用于全部选中、取消选择使用)
                _checkednodes: function (node, bool, isopall) {        // 设置多节点选中状态
                    this._checkednode(node, bool);                     // 设置当前节点
                    if (this._fnobject.options.cascade || isopall) {   // 级联选择节点 或 前台必须要全部节点
                        var tm_prefix = this._myfnid + "_sdptree_node_chk_";
                        var tm_nodecode = node.attr("id").replace(tm_prefix, "");
                        var tm_flag = true;
                        if ((bool) && (tm_nodecode != this._fnobject.options.rootcode)) {
                            var tm_pnodecode = this._hsnodes[tm_nodecode].supnodecode;      // 设置上级勾选
                            while (tm_flag) {
                                var pnode = this._sdptree.find("#" + tm_prefix + tm_pnodecode);
                                if (tm_pnodecode == this._fnobject.options.rootcode) {
                                    if (!pnode.prop("checked")) { this._checkednode(pnode, true); };
                                    tm_flag = false;
                                    break;
                                } else {
                                    if (!pnode.prop("checked")) { this._checkednode(pnode, true); };
                                    tm_pnodecode = this._hsnodes[tm_pnodecode].supnodecode;
                                };
                            };
                        };

                        // 设置下级勾选
                        var subnodes = null;
                        if (tm_nodecode == this._fnobject.options.rootcode) { subnodes = this._dtnodes; } else { subnodes = this._hsnodes[tm_nodecode]._childs; };
                        this._checkedsubnodes(subnodes, bool);
                        subnodes = null;
                    };
                },
                _checkednode: function (node, bool) {
                    node.removeclass("checkbox").removeclass("checkbox_check").addclass(((bool) ? "checkbox_check" : "checkbox")).prop("checked", bool);
                },
                _checkedsubnodes: function (nodes, bool) {
                    if (!nodes) { return; };
                    for (var tm1 = 0; tm1 < nodes.length; tm1++) {
                        var tm_node = this._sdptree.find("#" + this._myfnid + "_sdptree_node_chk_" + nodes[tm1].nodecode);
                        if (tm_node.length > 0) {
                            this._checkednode(tm_node, bool);
                            if (nodes[tm1]._childs) { this._checkedsubnodes(nodes[tm1]._childs, bool); };
                        };
                    };
                },
                _removehashnodes: function (nodecode) {
                    var rmnode = this._hsnodes[nodecode];
                    if (!rmnode) { return; };
                    if (rmnode._havechild) {
                        for (var tm2 = 0; tm2 < rmnode._childs.length; tm2++) {
                            this._removehashnodes(rmnode._childs[tm2].nodecode);
                        };
                    };

                    this._hsnodes.remove(nodecode);
                },
                _bindevent: function () {
                    var this_mynodes = this._sdptree.find("span[stype='node']");
                    var this_treeid = this._myfnid;
                    var this_rootnode = this._sdptree.find("#" + this_treeid + "_sdptree_node_span_" + this._fnobject.options.rootcode);
                    var _this = this;

                    if (this_rootnode.length > 0) {
                        this_rootnode.hover(function () {
                            $(this).addclass("node_hover").attr("title", $.text(this));
                        }, function () {
                            $(this).removeclass("node_hover").attr("title", "");
                        });
                    };
                    if (this_mynodes.length == 0) { return; };
                    this_mynodes.hover(function () {   // 性能比较 此方法直接绑定hover 比 $().each() 方法耗时少很多
                        var tmthisnode = _this._hsnodes[$(this).attr("id").replace(this_treeid + "_sdptree_node_span_", "")];
                        var tmtitle = "";
                        if (tmthisnode) { tmtitle = tmthisnode.nodetitle; };
                        if (!tmtitle) { tmtitle = $.text(this); };
                        $(this).addclass("node_hover").attr("title", tmtitle);
                    }, function () {
                        $(this).removeclass("node_hover").attr("title", "");
                    });
                }
            }
        };
    };
})(jquery);

 

       第五:网页端页面代码也贴出来

 

<!doctype html public "-//w3c//dtd xhtml 1.0 transitional//en" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>树 tree </title>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <meta http-equiv="x-ua-compatible" content="ie=edge" />
    <link href="css/tree.css" rel="stylesheet" type="text/css" />
    <script src="js/min-jquery-1.9.1.js" type="text/javascript"></script>
    <script src="js/basic.js" type="text/javascript"></script>
    <script src="js/tree_plug.js" type="text/javascript"></script>
    <script type="text/javascript">

        var nodesjson = {};
        var nodesxml = "";

        // 定义一个tree插件实例对象变量
        var treeplug = null;

        // 加载 tree
        function onloadtree() {

            // 创建一个tree插件实例
            treeplug = new $.fn.webtree();

            // 初始化插件对象内部参数
            treeplug.init($("div.sdp-tree"));

            var nditem = null;
            for (var i = 10; i < 20; i++) {

                // 第一级节点
                nditem = {
                    nodecode: string(i),
                    nodetext: "第一节点" + i,
                    nodetitle: "",
                    supnodecode: ""

                };
                treeplug.addnodeitem(nditem);

                // 第二级节点
                for (var j = 10; j < 20; j++) {
                    nditem = {
                        nodecode: string(i) + string(j),
                        nodetext: "第二节点" + string(i) + string(j),
                        nodetitle: "",
                        supnodecode: string(i)
                    };
                    treeplug.addnodeitem(nditem);

                    // 第三级节点
                    for (var k = 10; k < 20; k++) {
                        var tmcode = string(i) + string(j) + string(k);
                        nditem = {
                            nodecode: tmcode,
                            nodetext: "第二节点" + tmcode,
                            nodetitle: "",
                            supnodecode: string(i) + string(j)
                        };
                        treeplug.addnodeitem(nditem);
                    }
                }

            };

            treeplug.maketree();

        }

   
    </script>
</head>
<body>
    <div style="position: absolute; display: block; top: 10px; left: 50px;">
        <button onclick="onloadtree()">
            加载目录树</button>
    </div>
    <div class="sdp-tree" id="demo_tree" style="position: absolute; display: block; left: 50px;
        top: 50px; height: 500px; width: 400px;">
    </div>
</body>
</html>

 

       第六:最终显示效果

JS--插件: 树Tree 开发与实现

 

     第七:补充将js补充上来   basic.js

(function ($) {
    $.extend({
        replaceall: function (str, s1, s2) {
            if (str) {
                return str.replace(new regexp(s1, "gm"), s2)
            } else {
                return str
            }
        },
        hashtable: function () {
            hash = function () { };
            hash.prototype = {
                constructor: hash,
                add: function (okey, oval) {
                    if (!this.hasownproperty(okey)) {
                        this[okey] = oval
                    }
                },
                count: function () {
                    var _count = 0;
                    for (var icount in this) {
                        if (this.hasownproperty(icount)) {
                            _count++
                        }
                    };
                    return _count
                },
                remove: function (okey) {
                    if (this.hasownproperty(okey)) {
                        delete this[okey]
                    }
                },
                update: function (okey, oval) {
                    this[okey] = oval
                },
                has: function (okey) {
                    var type = typeof okey;
                    if (type === 'string' || type === 'number') {
                        return this.hasownproperty(okey)
                    } else if (type === 'function' && this.some(okey)) {
                        return true
                    };
                    return false
                },
                clear: function () {
                    for (var okey in this) {
                        if (this.hasownproperty(okey)) {
                            delete this[okey]
                        }
                    }
                },
                isempty: function () {
                    for (var okey in this) {
                        if (this.hasownproperty(okey)) {
                            return false
                        }
                    };
                    return true
                },
                each: function (fn) {
                    for (var okey in this) {
                        if (this.hasownproperty(okey)) {
                            fn.call(this, this[okey], okey, this)
                        }
                    }
                },
                map: function (fn) {
                    var hash = new hash;
                    for (var okey in this) {
                        if (this.hasownproperty(okey)) {
                            hash.add(okey, fn.call(this, this[okey], okey, this))
                        }
                    };
                    return hash
                },
                join: function (split) {
                    split = split !== undefined ? split : ',';
                    var rst = [];
                    this.each(function (oval) {
                        rst.push(oval)
                    });
                    return rst.join(split)
                },
                every: function (fn) {
                    for (var okey in this) {
                        if (this.hasownproperty(okey)) {
                            if (!fn.call(this, this[okey], okey, this)) {
                                return false
                            }
                        }
                    };
                    return true
                },
                some: function (fn) {
                    for (var okey in this) {
                        if (this.hasownproperty(okey)) {
                            if (fn.call(this, this[okey], okey, this)) {
                                return true
                            }
                        }
                    };
                    return false
                },
                find: function (okey) {
                    var type = typeof okey;
                    if (type === 'string' || type === 'number' && this.has(okey)) {
                        return this[okey]
                    } else if (type === 'function') {
                        for (var _okey in this) {
                            if (this.hasownproperty(_okey) && okey.call(this, this[_okey], _okey, this)) {
                                return this[_okey]
                            }
                        }
                    };
                    return null
                }
            };
            return new hash()
        },
        isnull: function (objval) {
            if (typeof (objval) == "undefined" || objval == null) {
                return true
            };
            if (typeof (objval) == "number" || typeof (objval) == "boolean") {
                return false
            };
            if (objval == "") {
                return true
            };
            try {
                if (objval.length == 0) {
                    return true
                };
                var strcomp = $.replaceall(string(objval), " ", "");
                if (strcomp == "" || strcomp == "&nbsp;" || strcomp.length == 0) {
                    return true
                } else {
                    return false
                }
            } catch (error) {
                return false
            }
        },
        isnumber: function (obj) {
            return (!isnan(obj) && typeof (obj) == "number")
        },
        newguid: function () {
            function s4() {
                return (((1 + math.random()) * 0x10000) | 0).tostring(16).substring(1)
            };
            return (s4() + s4() + "-" + s4() + "-" + s4() + "-" + s4() + "-" + s4() + s4() + s4()).touppercase()
        },
        loadxmlfile: function (xmlfilepath) {
            var retxmldoc = null;
            if (xmlfilepath) {
                $.ajax({
                    type: 'get',
                    async: false,
                    url: xmlfilepath,
                    datatype: 'xml',
                    success: function (xmldata) {
                        retxmldoc = xmldata
                    }
                })
            };
            return retxmldoc
        },
        loadxmlstring: function (xmlstr) {
            var retxmldoc = null;
            if (xmlstr) {
                try {
                    retxmldoc = $.parsexml(xmlstr)
                } catch (g) {
                    retxmldoc = null
                }
            };
            return retxmldoc
        },
        stopbubble: function (event) {
            event = event || window.event;
            $.preventdefault(event);
            $.stoppropagation(event);
            return false
        },
        preventdefault: function (event) {
            event = event || window.event;
            if (event.preventdefault) {
                event.preventdefault()
            };
            event.returnvalue = false
        },
        stoppropagation: function (event) {
            event = event || window.event;
            if (event.stoppropagation) {
                event.stoppropagation()
            };
            event.cancelbubble = true
        },
        runstrevent: function (strevent, e) {
            var reteventvalue = null;
            if (!strevent) {
                return reteventvalue
            };
            var _runevent = $.strtofunction(strevent);
            if (typeof (_runevent) == 'function') {
                try {
                    reteventvalue = _runevent.call(null, e)
                } catch (err) {
                    reteventvalue = err
                }
            } else {
                alert("错误:事件方法有误!" + strevent);
                reteventvalue = "error:事件方法有误!"
            };
            if (typeof (reteventvalue) == 'undefined') {
                reteventvalue = null
            };
            return reteventvalue
        },
        strtofunction: function (strevent) {
            if (typeof (strevent) == "function") {
                return strevent
            } else if (!strevent || typeof (strevent) != "string") {
                return null
            } else {
                try {
                    strevent = $.trim(string(strevent));
                    if (strevent.indexof('(') > 0) {
                        strevent = strevent.substring(0, strevent.indexof('('))
                    };
                    return (new function("return " + strevent))()
                } catch (error) {
                    return null
                }
            }
        },
        getjson_fromfile: function (filepath) {
            var jsonobj = null;
            if (filepath) {
                $.ajaxsettings.async = false;
                $.getjson(filepath,
                function (retdata) {
                    jsonobj = retdata
                });
                $.ajaxsettings.async = true
            };
            return jsonobj
        },
        getjson_fromstr: function (jsonstr) {
            var jsonobj = null;
            if (jsonstr) {
                try {
                    jsonobj = $.parsejson(jsonstr)
                } catch (error) {
                    jsonobj = null
                }
            };
            return jsonobj
        }

    });
})(jquery);

 

     第八:因为无法上传附件,所以只能提供外部链接地址:  tree_demo.rar