日常在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等)

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

  1. (function ($) {
  2. $.fn.webTree = function () {
  3. return {
  4. sdptype: "tree", // 树形目录
  5. myObject: null, // Tree 树Jquery对象 $("#treeID")
  6. myContainer: null, // Tree 包围树节点的容器Jquery对象[为了保证滚动条和位置的协调,特加入一个容器]
  7. myFnId: "", // Tree 内部使用ID[目录树控件可以不定义ID,此属性就是为无ID的情况下也能适用]
  8. sdpTree: null, // Tree 插件自动生成树节点的包围容器,与myContainer 容器非同一个容器,是在myContainer的内部
  9. focusNodeCode: null, // Tree 树当前获取到焦点的节点编码
  10. defaults: { // Tree 树默认相关参数
  11. sdpfixed: false, // Tree 是否设计器设计的固定目录树
  12. showroot: true, // Tree 是否显示根目录
  13. showline: true, // Tree 是否显示连接竖线
  14. showicon: true, // Tree 是否显示节点图片
  15. selecttype: "", // Tree 树节点选择类型 "":表示无选择按钮; checkbox:表示启用复选按钮; radio:表示启用单选按钮
  16. cascade: false, // Tree 开启复选按钮时,是否启用级联选择(自动勾选下级及所属上级)
  17. popmenu: false, // Tree 是否启用右击弹出菜单
  18. openall: false, // Tree 是否展开所有节点;false: 展开第一级
  19. rooticon: "", // Tree 根目录节点自定义显示图标文件完整路径名称 [平台设计的则放在对应的图片目录中]
  20. middefticon: "", // Tree 中间节点收缩自定显示图标文件完整路径名称
  21. midexpdicon: "", // Tree 中间节点展开自定显示图标文件完整路径名称
  22. endnodeicon: "", // Tree 末级节点显示自定显示图标文件完整路径名称
  23. customload: "", // Tree 树自定加载事件(事件名称字符串或事件方法)[主要目的:为了让右击刷新按钮能找到重新加载数据的源头方法]
  24. nodeclick: "", // Tree 树目录节点单击事件(事件名称字符串或事件方法)
  25. nodedblclick: "", // Tree 树目录节点双击事件(事件名称字符串或事件方法)
  26. checkedchange: "", // Tree 树目录节点选择改变事件(事件名称字符串或事件方法)[只有开启了选择,才有效]
  27. rootcode: "-1", // Tree 根节点Code ID(目的是为支持从中间节点进行加载目录树的功能)默认为-1
  28. roottext: "树形目录", // Tree 根目录节点名称
  29. rooturl: "" // Tree 根目录超连接URL地址
  30. },
  31. options: {}, // Tree 控件最终参数
  32. curNodes: [], // Tree 临时树节点数组(添加节点时临时储存)
  33.  
  34. // @ method: init() 插件实例初始化
  35. // @ depict: 执行插件实例的初始化
  36. // @ params: [object] element 控件对象
  37. // @ pbtype: 外部调用方法
  38. init: function (element) { // 树初始化
  39. this.myObject = $(element);
  40. if (this.myObject.length == 0) { return; };
  41. this.myContainer = this.myObject.children('div[sdptype="treebase"]');
  42. if (this.myContainer.length == 0) { // 重新创建
  43. this.myObject.empty().append('<div sdptype="treebase" class="sdp-tree-base" ></div>');
  44. this.myContainer = this.myObject.children('div[sdptype="treebase"]');
  45. };
  46. this.myFnId = this.myObject.attr("id") || $.newGuid(); // Tree 内部使用ID 用于创建NODE各个节点
  47. this.myContainer.empty().append('<div class="sdp-tree-in"></div>'); // 添加一个正式的目录树容器
  48. this.sdpTree = this.myContainer.find("div.sdp-tree-in"); // 获取sdpTree容器Jquery对象
  49.  
  50. // 设置内部参数
  51. this._methods._fnObject = this;
  52. this._methods._myObject = this.myObject;
  53. this._methods._myContainer = this.myContainer;
  54. this._methods._myFnId = this.myFnId;
  55. this._methods._sdpTree = this.sdpTree;
  56.  
  57. // 加载绑定参数
  58. this._loadParam();
  59. this._bindEvent();
  60. },
  61.  
  62. // @ method: setOptions() 自定设置控件Options属性值
  63. // @ depict: 自定设置控件Options属性值
  64. // @ params: [object] options 树形配置参数 Json格式
  65. // @ pbtype: 外部调用方法
  66. setOptions: function (options) {
  67. if (!options) { options = {}; };
  68. this.options = $.extend({}, this.options, options); // 合并目录树相关参数
  69. },
  70.  
  71. // @ method: nodeItem() 创建一个空节点参数对象
  72. // @ depict: 通过此方法创建一个空节点参数对象,用于前台初始化增加节点或执行插入节点使用,通过扩展方法来组合参数
  73. // @ return: [array]节点{ // 节点参数
  74. // @ nodecode: "", // string 节点编码
  75. // @ nodetext: "", // string 节点名称文本
  76. // @ nodetitle: "", // string 节点鼠标移入显示提示文本
  77. // @ supnodecode: "", // string 节点所属上级即父节点编码
  78. // @ nodeurl: "", // string 节点关联链接地址
  79. // @ iconexpand: "", // string 节点展开时显示图标完整路径
  80. // @ iconcollapse: "" // string 节点收缩时显示图标完整路径
  81. // @ }
  82. // @ pbtype: 外部调用方法
  83. nodeItem: function () {
  84. return {
  85. nodecode: "",
  86. nodetext: "",
  87. nodetitle: "",
  88. supnodecode: "",
  89. nodeurl: "",
  90. iconexpand: "", // 节点展开时显示图标完整路径
  91. iconcollapse: "" // 节点收缩时显示图标完整路径
  92. };
  93. },
  94.  
  95. // 创建树形目录
  96. // 由开发人员通过以下3种方式创建树数据
  97. // 1、loadJson(Json) JSON 对象目录树节点数组(一次性完成)
  98. // 2、loadXml(xml) XML字符串格式的节点数据(一次性完成)
  99. // 3、addNodeItem(nodeItem) 通过手工一条一条的添加节点项目(需要两步完成)
  100. // 3、makeTree() 再手工调用此方法,则可以创建树
  101.  
  102. // @ method: addNodeItem() 添加目录树节点
  103. // @ depict: 通过此方法向目录树添加节点数据
  104. // @ params: [array] nodeItem{} 格式参数数组
  105. // @ pbtype: 外部调用方法
  106. addNodeItem: function (nodeItem) {
  107. var _curNodeItem = $.extend({}, new this.nodeItem(), nodeItem); // 合并参数
  108. if ($.isNull(_curNodeItem.nodecode)) { return; };
  109. if ($.isNull(_curNodeItem.supnodecode)) { _curNodeItem.supnodecode = this.options.rootcode; };
  110. this.curNodes[this.curNodes.length] = { // 在临时树节点数组中添加待加入的节点信息
  111. nodecode: _curNodeItem.nodecode,
  112. nodetext: _curNodeItem.nodetext || "",
  113. nodetitle: _curNodeItem.nodetitle || "",
  114. supnodecode: _curNodeItem.supnodecode,
  115. nodeurl: _curNodeItem.nodeurl || "",
  116. iconexpand: _curNodeItem.iconexpand || "",
  117. iconcollapse: _curNodeItem.iconcollapse || "",
  118. _parent: null, // 所属的父节点
  119. _firstFlag: false, // 本级中的首位 标志
  120. _lastFlag: false, // 本级中的末位 标志
  121. _nodeLevel: 0, // 当前节点级别 默认0
  122. _haveChild: false, // 是否包含下级
  123. _childs: [] // 子节点的数组
  124. };
  125. _curNodeItem = null;
  126. },
  127.  
  128. // @ method: loadXml() 加载XML格式的节点数据
  129. // @ depict: 直接加载解析XML格式的节点数据
  130. // @ params: [object] xml XML格式的节点字符串或XmlDocument对象
  131. // @ pbtype: 外部调用方法
  132. loadXml: function (xml) {
  133. if ($.isNull(this.options.rootcode)) { this.options.rootcode = "-1"; }; // 设置根节点编码
  134. this.curNodes = []; // 清空变量数据
  135. if (xml) {
  136. var currXmlDoc = null;
  137. if (typeof (xml) == "object") {
  138. currXmlDoc = xml;
  139. } else { // string
  140. currXmlDoc = $.loadXmlString(String(xml));
  141. };
  142. if (currXmlDoc) { // 再次判定 开始解析
  143. for (var nn = 0; nn < currXmlDoc.documentElement.childNodes.length; nn++) {
  144. var _curNode = currXmlDoc.documentElement.childNodes[nn];
  145. var _curAddItem = new this.nodeItem();
  146. for (var jj = 0; jj < _curNode.childNodes.length; jj++) {
  147. var _subItem = _curNode.childNodes[jj];
  148. switch (_subItem.tagName.toLowerCase()) {
  149. case "nodecode":
  150. _curAddItem.nodecode = $(_subItem).text();
  151. break;
  152. case "nodetext":
  153. _curAddItem.nodetext = $(_subItem).text();
  154. break;
  155. case "nodetitle":
  156. _curAddItem.nodetitle = $(_subItem).text();
  157. break;
  158. case "supnodecode":
  159. _curAddItem.supnodecode = $(_subItem).text();
  160. break;
  161. case "nodeurl":
  162. _curAddItem.nodeurl = $(_subItem).text();
  163. break;
  164. case "iconexpand":
  165. _curAddItem.iconexpand = $(_subItem).text();
  166. break;
  167. case "iconcollapse":
  168. _curAddItem.iconcollapse = $(_subItem).text();
  169. break;
  170. };
  171. };
  172.  
  173. this.addNodeItem(_curAddItem);
  174. }
  175. }
  176. };
  177.  
  178. this.makeTree();
  179.  
  180. // 说明:采用XML字符串格式
  181. // <root>
  182. // <item> // 每一个节点 内包含多个数据值
  183. // <nodecode><![CDATA[节点编码值]]></nodecode>"; 注意节点 tagName:nodecode nodetext 等 不允许变更 因为程序内部是直接采用这个名字来获取的
  184. // <nodetext><![CDATA[节点名称文本 ]]></nodetext>";
  185. // <nodetitle><![CDATA[节点鼠标移入显示提示文本]]></nodetitle>";
  186. // <supnodecode><![CDATA[节点所属上级即父节点编码]]></supnodecode>";
  187. // <nodeurl><![CDATA[节点关联链接地址]]></nodeurl>";
  188. // <iconexpand><![CDATA[节点展开时显示图标路径]]></iconexpand>";
  189. // <iconcollapse><![CDATA[节点收缩时显示图标路径]]></iconcollapse>";
  190. // </item>
  191. //</root>
  192. },
  193.  
  194. // @ method: loadJson() 加载JSON格式的节点数据
  195. // @ depict: 直接加载解析JSON格式的节点数据
  196. // @ params: [array] json JSON数据对象
  197. // @ pbtype: 外部调用方法
  198. loadJson: function (json) {
  199. if (!this.options.rootcode) { this.options.rootcode = "-1"; }; // 设置根节点编码
  200. this.curNodes = []; // 清空变量数据
  201. if (json) {
  202. for (var jj = 0; jj < json.length; jj++) {
  203. var jsonItem = json[jj];
  204. if (!jsonItem.nodecode) { continue; }; // 节点编码不允许为空
  205.  
  206. var addsItem = new this.nodeItem();
  207. addsItem.nodecode = jsonItem.nodecode;
  208. addsItem.nodetext = jsonItem.nodetext || "";
  209. addsItem.nodetitle = jsonItem.nodetitle || "";
  210. addsItem.supnodecode = jsonItem.supnodecode || "";
  211. addsItem.nodeurl = jsonItem.nodeurl || "";
  212. addsItem.iconexpand = jsonItem.iconexpand || "";
  213. addsItem.iconcollapse = jsonItem.iconcollapse || "";
  214.  
  215. this.addNodeItem(addsItem); // 添加节点
  216. };
  217. };
  218. this.makeTree();
  219.  
  220. // JSON 格式 是一个Array 数组 每项为一个 nodeItem 对象的参数
  221. // [{ nodecode: "", nodetext: "", nodetitle: "",supnodecode: "",nodeurl: "",iconexpand: "",iconcollapse: ""},
  222. // {},...
  223. // ]
  224. },
  225.  
  226. // @ method: loadNodeItems() 加载NodeItem Array节点数组数据
  227. // @ depict: 直接加载NodeItem Array节点数组数据
  228. // @ params: [array] itemArray NodeItem Array节点数组数据
  229. // @ pbtype: 外部调用方法
  230. loadNodeItems: function (itemArray) {
  231. if (!itemArray) { itemArray = []; };
  232. for (var jj = 0; jj < itemArray.length; jj++) {
  233. var ndItem = itemArray[jj];
  234. if (!ndItem.nodecode) { continue; }; // 节点编码不允许为空
  235. this.addNodeItem(ndItem); // 添加节点
  236. };
  237. this.makeTree();
  238. },
  239.  
  240. // @ method: makeTree() 创建生成树
  241. // @ depict: 创建生成树对象的所有节点并显示出来
  242. // @ 此方法执行之前需要先获取或手工添加完成所有树节点
  243. // @ 前台JS 必须通过 addNodeItem(nodeItem) 方法添加节点
  244. // @ pbtype: 外部内部调用方法
  245. makeTree: function () {
  246. this.sdpTree.empty();
  247. this._methods._createTree();
  248. },
  249.  
  250. // @ method: appendNode() 插入节点
  251. // @ depict: 通过此方法向目录树插入新的节点
  252. // @ params: [array] nodeItem {} 格式参数数组
  253. // @ pbtype: 外部调用方法
  254. appendNode: function (nodeItem) {
  255. var _this = this, P = this.options;
  256. var curNewNode = $.extend({}, new this.nodeItem(), nodeItem); // 合并节点输入参数
  257. if ($.isNull(curNewNode.nodecode)) { return; };
  258. if ($.isNull(curNewNode.supnodecode)) { curNewNode.supnodecode = P.rootcode; };
  259. if (this._methods._hsNodes[curNewNode.nodecode]) { return; }; // 节点编码已经存在,不执行添加
  260. if (P.rootcode != curNewNode.supnodecode && !this._methods._hsNodes[curNewNode.supnodecode]) { return; }; // 父节点不为根节点时,父节点数据不存在,则不执行
  261. var newNode = {
  262. nodecode: curNewNode.nodecode,
  263. nodetext: curNewNode.nodetext || "",
  264. nodetitle: curNewNode.nodetitle || "",
  265. supnodecode: curNewNode.supnodecode,
  266. nodeurl: curNewNode.nodeurl || "",
  267. iconexpand: curNewNode.iconexpand || "",
  268. iconcollapse: curNewNode.iconcollapse || "",
  269. _parent: null, // 所属的父节点
  270. _firstFlag: false, // 本级中的首位 标志
  271. _lastFlag: false, // 本级中的末位 标志
  272. _nodeLevel: 0, // 当前节点级别 默认0
  273. _haveChild: false, // 是否包含下级
  274. _childs: [] // 子节点的数组
  275. };
  276. curNewNode = null;
  277. if (P.rootcode == newNode.supnodecode) {
  278. newNode._parent = null;
  279. newNode._nodeLevel = 1;
  280. var len = this._methods._dtNodes.length;
  281. if (len > 0) {
  282. this._methods._dtNodes[len - 1]._lastFlag = false;
  283. newNode._lastFlag = true;
  284. } else {
  285. newNode._firstFlag = true;
  286. newNode._lastFlag = true;
  287. };
  288. this._methods._dtNodes.push(newNode); // 添加到第一级中
  289. } else {
  290. var curParent = this._methods._hsNodes[newNode.supnodecode];
  291. newNode._parent = curParent;
  292. newNode._nodeLevel = curParent._nodeLevel + 1;
  293. if (curParent._haveChild) {
  294. curParent._childs[curParent._childs.length - 1]._lastFlag = false;
  295. newNode._lastFlag = true;
  296. } else {
  297. curParent._haveChild = true;
  298. newNode._firstFlag = true;
  299. newNode._lastFlag = true;
  300. };
  301. curParent._childs.push(newNode); // 添加到父节点的子节点数组中
  302. };
  303. this._methods._hsNodes.add(newNode.nodecode, newNode); // 加入HASH
  304.  
  305. // 创建节点
  306. var curNodes = []; curNodes.push(newNode);
  307. var $appNode = $(this._methods._createNodes(curNodes));
  308. if (newNode.nodecode == P.rootcode) {
  309. if (P.showroot) { this.sdpTree.find("#" + this.myFnId + "_sdptree_node_clip_" + P.rootcode).append($appNode); } else { this.sdpTree.append($appNode); };
  310. } else {
  311. var $parent_clip = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_clip_" + newNode.supnodecode);
  312. if ($parent_clip.length > 0) {
  313. $parent_clip.append($appNode);
  314. }
  315. else {
  316. $now_clip = $('<div id="' + this.myFnId + '_sdptree_node_clip_' + newNode.supnodecode + '" class="clipdiv" stype="clip" style="display: block" ></div>');
  317. $now_clip.append($appNode);
  318. this.sdpTree.find("#" + this.myFnId + "_sdptree_node_full_" + newNode.supnodecode).after($now_clip);
  319. };
  320. };
  321.  
  322. // 更新节点样式
  323. if (newNode.supnodecode == P.rootcode) { // 上级为根节点的时候,直接更新前一个节点
  324. if (this._methods._dtNodes.length > 1) {
  325. var _prevCode = this._methods._dtNodes[this._methods._dtNodes.length - 2].nodecode;
  326. this._methods._updateNode(_prevCode);
  327. };
  328. } else { // 上级不为根节点时候,直接更新此上级节点
  329. this._methods._updateNode(newNode.supnodecode);
  330. };
  331.  
  332. // 绑定节点Hover事件
  333. $appNode.find("span[stype='node']").hover(function () {
  334. var tmTitle = _this._methods._hsNodes[$(this).attr("id").replace(_this.myFnId + "_sdptree_node_span_", "")].nodetitle;
  335. if (!tmTitle) { tmTitle = $.text(this); };
  336. $(this).addClass("node_hover").attr("title", tmTitle);
  337. }, function () {
  338. $(this).removeClass("node_hover").attr("title", "");
  339. });
  340. },
  341.  
  342. // @ method: deleteNode() 删除树节点
  343. // @ depict: 删除指定节点编码的树节点
  344. // @ params: [string] nodeCode 节点编码
  345. // @ pbtype: 外部调用方法
  346. deleteNode: function (nodeCode) {
  347. if ($.isNull(nodeCode)) { return; };
  348. if (nodeCode == this.options.rootcode) {
  349. this.clearAll();
  350. } else {
  351. if (!this._methods._hsNodes[nodeCode]) { return; };
  352. var removeNode = this._methods._hsNodes[nodeCode];
  353. var prevNodeCode = this.getPrevNodeCode(nodeCode);
  354. var tm2 = 0;
  355.  
  356. // 首先删除HASH表中的所有子节点 先不删除本身节点
  357. if (removeNode._haveChild) {
  358. for (var tm1 = 0; tm1 < removeNode._childs.length; tm1++) {
  359. this._methods._removeHashNodes(removeNode._childs[tm1].nodecode);
  360. };
  361. };
  362.  
  363. // 移除dtNodes数组中的节点项
  364. if (removeNode._parent) {
  365. for (tm2 = 0; tm2 < removeNode._parent._childs.length; tm2++) {
  366. if (removeNode._parent._childs[tm2].nodecode == nodeCode) {
  367. removeNode._parent._childs.splice(tm2--, 1);
  368. break;
  369. };
  370. };
  371. } else { // 根目录下的第一级
  372. for (tm2 = 0; tm2 < this._methods._dtNodes.length; tm2++) {
  373. if (this._methods._dtNodes[tm2].nodecode == nodeCode) {
  374. this._methods._dtNodes.splice(tm2--, 1);
  375. break;
  376. };
  377. };
  378. };
  379.  
  380. // 移除DOM Node对象
  381. var rmNodeFullDom = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_full_" + nodeCode);
  382. var rmNodeClipDom = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_clip_" + nodeCode);
  383. if (rmNodeFullDom.length > 0) { rmNodeFullDom.remove(); };
  384. if (rmNodeClipDom.length > 0) { rmNodeClipDom.remove(); };
  385.  
  386. // 更新Node父节点的数据
  387. var parentND = removeNode._parent;
  388. if (!parentND) {
  389. for (tm2 = 0; tm2 < this._methods._dtNodes.length; tm2++) {
  390. this._methods._dtNodes[tm2]._firstFlag = (tm2 == 0) ? true : false;
  391. this._methods._dtNodes[tm2]._lastFlag = (tm2 == (this._methods._dtNodes.length - 1)) ? true : false;
  392. };
  393. } else {
  394. if (parentND._childs.length > 0) {
  395. for (tm2 = 0; tm2 < parentND._childs.length; tm2++) {
  396. parentND._childs[tm2]._firstFlag = (tm2 == 0) ? true : false;
  397. parentND._childs[tm2]._lastFlag = (tm2 == (parentND._childs.length - 1)) ? true : false;
  398. };
  399. } else {
  400. parentND._haveChild = false;
  401. };
  402. };
  403.  
  404. this._methods._hsNodes.remove(removeNode.nodecode); // 从Hash表删除自己
  405.  
  406. // 更新节点样式
  407. if (parentND) {
  408. this._methods._updateNode(parentND.nodecode); // 更新父级节点显示样式
  409. } else {
  410. this._methods._updateNode(prevNodeCode); // 更新前一级节点显示样式
  411. };
  412. };
  413. },
  414.  
  415. // @ method: clearAll() 清空树节点
  416. // @ depict: 清空树所有节点包括参数
  417. // @ pbtype: public 外部调用方法
  418. clearAll: function () {
  419. this.focusNodeCode = null;
  420. this.curNodes = [];
  421. this._methods._myNodes = [];
  422. this._methods._dtNodes = null;
  423. this._methods._hsNodes = null;
  424. this.sdpTree.empty();
  425. },
  426.  
  427. // @ method: getNode() 获取节点对象DIV
  428. // @ depict: 根据节点 NodeCode 来获取
  429. // @ params: [string] nodeCode 节点编码
  430. // @ return: [object] 返回节点DOM元素对象
  431. // @ pbtype: 外部调用方法
  432. getNode: function (nodeCode) {
  433. var retNode = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_full_" + nodeCode);
  434. return ((retNode.length > 0) ? retNode[0] : null);
  435. },
  436.  
  437. // @ method: getNodeParams() 获取节点的所有参数
  438. // @ depict: 根据节点 NodeCode 来获取
  439. // @ params: [string] nodeCode 节点编码
  440. // @ return: [object] 返回节点参数对象
  441. // @ pbtype: 外部调用方法
  442. getNodeParams: function (nodeCode) {
  443. var retNodeItem = null;
  444. if (nodeCode == null) { return retNodeItem; };
  445. if (nodeCode == this.options.rootcode) { // 树根节点
  446. retNodeItem = new this.nodeItem();
  447. retNodeItem.nodecode = this.options.rootcode;
  448. retNodeItem.nodetext = this.options.roottext;
  449. retNodeItem.nodeurl = this.options.rooturl;
  450. retNodeItem.iconcollapse = this.options.rooticon;
  451. } else { // 普通节点
  452. retNodeItem = this._methods._hsNodes[nodeCode]; // 从数组中获取此节点的所有值
  453. };
  454. return retNodeItem;
  455. },
  456.  
  457. // @ method: getNodeCode() 获取节点编码
  458. // @ depict: 根据节点对象(通过getNode() 方法获取的节点对象) 来获取此对象的节点ID
  459. // @ params: node object 节点DOM对象
  460. // @ return: string 返回节点对象的ID
  461. // @ pbtype: 外部调用方法
  462. getNodeCode: function (node) {
  463. var retNodeCode = null;
  464. if (node) {
  465. var tmID = $(node).attr("id");
  466. if (tmID) {
  467. retNodeCode = tmID.replace(this.myFnId + "_sdptree_node_full_", "");
  468. };
  469. };
  470. return retNodeCode;
  471. },
  472.  
  473. // @ method: getPrevNodeCode() 获取指定节点的前一个节点的节点编码NodeCode
  474. // @ depict: 根据指定的节点NodeCode来获取其前一个节点NodeCode 节点编码
  475. // @ params: nodeCode string 指定的节点编码
  476. // @ return: string 返回指定的节点NodeCode的前一个节点编码NodeCode
  477. // @ pbtype: 外部调用方法
  478. getPrevNodeCode: function (nodeCode) {
  479. var _prevCode = null;
  480. var _curtNode = this._methods._hsNodes[nodeCode];
  481. if (_curtNode) {
  482. if (_curtNode._firstFlag) { return _prevCode; };
  483. if (_curtNode.supnodecode == this.options.rootcode) {
  484. for (var tm0 = 0; tm0 < this._methods._dtNodes.length; tm0++) {
  485. if (this._methods._dtNodes[tm0].nodecode == nodeCode) {
  486. _prevCode = this._methods._dtNodes[tm0 - 1].nodecode;
  487. break;
  488. };
  489. };
  490. } else {
  491. var _parentND = _curtNode._parent;
  492. for (var tm1 = 0; tm1 < _parentND._childs.length; tm1++) {
  493. if (_parentND._childs[tm1].nodecode == nodeCode) {
  494. _prevCode = _parentND._childs[tm1 - 1].nodecode;
  495. break;
  496. };
  497. };
  498. };
  499. };
  500. return _prevCode;
  501. },
  502.  
  503. // @ method: getNextNodeCode() 获取指定节点的下一个节点编码
  504. // @ depict: 根据指定的节点编码来获取其后一个节点编码NodeCode
  505. // @ params: nodeCode string 指定的节点编码
  506. // @ return: object 返回指定的节点的后一个节点编码字符串
  507. // @ pbtype: 外部调用方法
  508. getNextNodeCode: function (nodeCode) {
  509. var _nextCode = null;
  510. var _curtNode = this._methods._hsNodes[nodeCode];
  511. if (_curtNode) {
  512. if (_curtNode._lastFlag) { return _nextCode; };
  513. if (_curtNode.supnodecode == this.options.rootcode) {
  514. for (var tm0 = 0; tm0 < this._methods._dtNodes.length; tm0++) {
  515. if (this._methods._dtNodes[tm0].nodecode == nodeCode) {
  516. _nextCode = this._methods._dtNodes[tm0 + 1].nodecode;
  517. break;
  518. };
  519. };
  520. } else {
  521. var _parentND = _curtNode._parent;
  522. for (var tm1 = 0; tm1 < _parentND._childs.length; tm1++) {
  523. if (_parentND._childs[tm1].nodecode == nodeCode) {
  524. _nextCode = _parentND._childs[tm1 + 1].nodecode;
  525. break;
  526. };
  527. };
  528. };
  529. };
  530. return _nextCode;
  531. },
  532.  
  533. // @ method: getParentNodeCode() 获取指定节点的父级节点编码
  534. // @ depict: 根据节点编码来获取其父级节点编码
  535. // @ params: nodeCode string 指定的节点编码
  536. // @ return: string 返回指定的节点编码的父级节点编码
  537. // @ pbtype: 外部调用方法
  538. getParentNodeCode: function (nodeCode) {
  539. var _parentNodeCode = null;
  540. if (this._methods._hsNodes[nodeCode]) {
  541. _parentNodeCode = this._methods._hsNodes[nodeCode].supnodecode;
  542. };
  543. return _parentNodeCode;
  544. },
  545.  
  546. // @ method: getFocusNodeCode() 获取目录树当前获取到焦点的节点编码
  547. // @ depict: 获取当前目录中,获取到焦点的即选中的节点编码 NodeCode
  548. // @ return: string 返回节点编码字符串
  549. // @ pbtype: 外部调用方法
  550. getFocusNodeCode: function () {
  551. return this.focusNodeCode;
  552. },
  553.  
  554. // @ method: getNodeLevel() 获取节点级别层次
  555. // @ depict: 根据节点编码来获取 此节点的层次级别
  556. // @ params: nodeCode string 节点编码
  557. // @ return: number 节点层次级别,无效返回-1
  558. // @ pbtype: 外部调用方法
  559. getNodeLevel: function (nodeCode) {
  560. if (nodeCode == this.options.rootcode) {
  561. return 0;
  562. } else {
  563. if (this._methods._hsNodes[nodeCode]) {
  564. return (this._methods._hsNodes[nodeCode])._nodeLevel;
  565. } else {
  566. return -1;
  567. };
  568. };
  569. },
  570.  
  571. // @ method: getNodeText() 获取节点文本值
  572. // @ depict: 根据节点编码来获取节点文本值
  573. // @ params: nodeCode string 节点编码
  574. // @ return: string 节点文本值
  575. // @ pbtype: 外部调用方法
  576. getNodeText: function (nodeCode) {
  577. var tm_Node = this.getNode(nodeCode);
  578. if (tm_Node) { return $(tm_Node).text(); };
  579. return null;
  580. },
  581.  
  582. // @ method: getNodeVal() 获取节点所有值
  583. // @ depict:根据节点编码 获取节点的所有值
  584. // @ params: nodeCode string 节点编码
  585. // @ return: Array {} 节点数据数组对象
  586. // @ pbtype: 外部调用方法
  587. getNodeVal: function (nodeCode) {
  588. var curNodeItem = new this.nodeItem();
  589. if (nodeCode == this.options.rootcode) {
  590. curNodeItem.nodecode = this.options.rootcode;
  591. curNodeItem.nodetext = this.options.roottext;
  592. curNodeItem.nodetitle = "";
  593. curNodeItem.supnodecode = "";
  594. curNodeItem.nodeurl = this.options.rooturl;
  595. curNodeItem.iconexpand = this.options.rooticon;
  596. curNodeItem.iconcollapse = this.options.rooticon;
  597. } else {
  598. var tm_Node = this._methods._hsNodes[nodeCode];
  599. if (tm_Node) {
  600. curNodeItem.nodecode = tm_Node.nodecode;
  601. curNodeItem.nodetext = tm_Node.nodecode;
  602. curNodeItem.nodetitle = tm_Node.nodecode;
  603. curNodeItem.supnodecode = tm_Node.nodecode;
  604. curNodeItem.nodeurl = tm_Node.nodeurl;
  605. curNodeItem.iconexpand = tm_Node.iconexpand;
  606. curNodeItem.iconcollapse = tm_Node.iconcollapse;
  607. };
  608. };
  609. return curNodeItem;
  610. },
  611.  
  612. // @ method: hideNode() 隐藏指定节点
  613. // @ depict: 根据节点编码 执行隐藏指定树节点对象
  614. // @ params: nodeCode string 节点编码
  615. // @ pbtype: 外部调用方法
  616. hideNode: function (nodeCode) {
  617. if (this.options.rootcode == nodeCode) { return; };
  618. var tm_MyNode = this.getNode(nodeCode);
  619. if (!tm_MyNode) { return; };
  620. var tm_SubNode = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_clip_" + nodeCode);
  621. $(tm_MyNode).hide();
  622. if (tm_SubNode.length > 0) { $(tm_SubNode).hide(); };
  623. },
  624.  
  625. // @ method: showNode() 显示指定节点
  626. // @ depict: 根据节点编码 执行显示指定树节点对象
  627. // @ params: nodeCode string 节点编码
  628. // @ pbtype: 外部调用方法
  629. showNode: function (nodeCode) {
  630. if (this.options.rootcode == nodeCode) { return; };
  631. var tm_MyNode = this.getNode(nodeCode);
  632. if (tm_MyNode) {
  633. $(tm_MyNode).show();
  634. this.collapseNode(nodeCode);
  635. };
  636. },
  637.  
  638. // @ method: setShowTreeLine() 设置树节点连线显示与否
  639. // @ depict: 设置显示、隐藏节点连线 [此功能只有当树期初设置为显示树节点连线的时候才起作用]
  640. // @ params: boolValue boolean 说明:true 表示显示连接线 false 表示不显示
  641. // @ pbtype: 外部调用方法
  642. setShowTreeLine: function (boolValue) {
  643. if (!this.options.showline) { return; };
  644. var plusList = this.sdpTree.find("span[stype='plus']");
  645. var lineList = this.sdpTree.find("span[stype='line']");
  646. var tm0 = 0;
  647. if ((boolValue) && boolValue == true) {
  648. for (tm0 = 0; tm0 < plusList.length; tm0++) {
  649. if ($(plusList[tm0]).prop("open")) {
  650. if ($(plusList[tm0]).hasClass("node_expd_0n")) {
  651. switch ($(plusList[tm0]).attr("collclass")) {
  652. case "node_plug_1l":
  653. $(plusList[tm0]).removeClass("node_plug_0n");
  654. $(plusList[tm0]).removeClass("node_expd_0n");
  655. $(plusList[tm0]).addClass("node_plug_1l");
  656. $(plusList[tm0]).addClass("node_expd_1l");
  657. break;
  658. case "node_plug_2b":
  659. $(plusList[tm0]).removeClass("node_plug_0n");
  660. $(plusList[tm0]).removeClass("node_expd_0n");
  661. $(plusList[tm0]).addClass("node_plug_2b");
  662. $(plusList[tm0]).addClass("node_expd_2b");
  663. break;
  664. case "node_plug_2t":
  665. $(plusList[tm0]).removeClass("node_plug_0n");
  666. $(plusList[tm0]).removeClass("node_expd_0n");
  667. $(plusList[tm0]).addClass("node_plug_2t");
  668. $(plusList[tm0]).addClass("node_expd_2t");
  669. break;
  670. case "node_plug_3a":
  671. $(plusList[tm0]).removeClass("node_plug_0n");
  672. $(plusList[tm0]).removeClass("node_expd_0n");
  673. $(plusList[tm0]).addClass("node_plug_3a");
  674. $(plusList[tm0]).addClass("node_expd_3a");
  675. break;
  676. }
  677. }
  678. } else {
  679. if ($(plusList[tm0]).hasClass("node_plug_0n")) {
  680. $(plusList[tm0]).removeClass("node_plug_0n");
  681. $(plusList[tm0]).addClass($(plusList[tm0]).attr("collclass"));
  682. }
  683. }
  684. };
  685. for (tm0 = 0; tm0 < lineList.length; tm0++) {
  686. if (($(lineList[tm0]).hasClass("node_line_10")) && ($(lineList[tm0]).hasClass("nullimg"))) { $(lineList[tm0]).removeClass("nullimg"); };
  687. if (($(lineList[tm0]).hasClass("node_line_11")) && ($(lineList[tm0]).hasClass("nullimg"))) { $(lineList[tm0]).removeClass("nullimg"); };
  688. if (($(lineList[tm0]).hasClass("node_line_20")) && ($(lineList[tm0]).hasClass("nullimg"))) { $(lineList[tm0]).removeClass("nullimg"); };
  689. if (($(lineList[tm0]).hasClass("node_line_21")) && ($(lineList[tm0]).hasClass("nullimg"))) { $(lineList[tm0]).removeClass("nullimg"); };
  690. if (($(lineList[tm0]).hasClass("node_line_3n")) && ($(lineList[tm0]).hasClass("nullimg"))) { $(lineList[tm0]).removeClass("nullimg"); };
  691. };
  692. } else {
  693. for (tm0 = 0; tm0 < plusList.length; tm0++) {
  694. var $plusObj = $(plusList[tm0]);
  695. if ($plusObj.prop("open")) {
  696. if ($plusObj.hasClass("node_expd_1l")) {
  697. $plusObj.removeClass("node_plug_1l").removeClass("node_expd_1l").addClass("node_plug_0n").addClass("node_expd_0n").attr("collclass", "node_plug_1l");
  698. } else if ($plusObj.hasClass("node_expd_2b")) {
  699. $plusObj.removeClass("node_plug_2b").removeClass("node_expd_2b").addClass("node_plug_0n").addClass("node_expd_0n").attr("collclass", "node_plug_2b");
  700. } else if ($plusObj.hasClass("node_expd_2t")) {
  701. $plusObj.removeClass("node_plug_2t").removeClass("node_expd_2t").addClass("node_plug_0n").addClass("node_expd_0n").attr("collclass", "node_plug_2t");
  702. } else if ($plusObj.hasClass("node_expd_3a")) {
  703. $plusObj.removeClass("node_plug_3a").removeClass("node_expd_3a").addClass("node_plug_0n").addClass("node_expd_0n").attr("collclass", "node_plug_3a");
  704. };
  705. } else {
  706. if ($plusObj.hasClass("node_plug_1l")) {
  707. $plusObj.removeClass("node_plug_1l").addClass("node_plug_0n").attr("collclass", "node_plug_1l");
  708. } else if ($plusObj.hasClass("node_plug_2b")) {
  709. $plusObj.removeClass("node_plug_2b").addClass("node_plug_0n").attr("collclass", "node_plug_2b");
  710. } else if ($plusObj.hasClass("node_plug_2t")) {
  711. $plusObj.removeClass("node_plug_2t").addClass("node_plug_0n").attr("collclass", "node_plug_2t");
  712. } else if ($plusObj.hasClass("node_plug_3a")) {
  713. $plusObj.removeClass("node_plug_3a").addClass("node_plug_0n").attr("collclass", "node_plug_3a");
  714. };
  715. };
  716. };
  717. for (tm0 = 0; tm0 < lineList.length; tm0++) {
  718. var $lineObj = $(lineList[tm0]);
  719. if (($lineObj.hasClass("node_line_10")) && (!$lineObj.hasClass("nullimg"))) { $lineObj.addClass("nullimg"); };
  720. if (($lineObj.hasClass("node_line_11")) && (!$lineObj.hasClass("nullimg"))) { $lineObj.addClass("nullimg"); };
  721. if (($lineObj.hasClass("node_line_20")) && (!$lineObj.hasClass("nullimg"))) { $lineObj.addClass("nullimg"); };
  722. if (($lineObj.hasClass("node_line_21")) && (!$lineObj.hasClass("nullimg"))) { $lineObj.addClass("nullimg"); };
  723. if (($lineObj.hasClass("node_line_3n")) && (!$lineObj.hasClass("nullimg"))) { $lineObj.addClass("nullimg"); };
  724. };
  725. };
  726. },
  727.  
  728. // @ method: setShowNodeIcon() 设置树节点ICON小图标显示与否
  729. // @ depict:设置树节点是否显示ICON小图标
  730. // @ params: boolValue boolean 说明:true 表示显示 false 表示不显示
  731. // @ pbtype: 外部调用方法
  732. setShowNodeIcon: function (boolValue) {
  733. var tmDisplay = ((boolValue) && boolValue == true) ? "inline-block" : "none";
  734. var tmIcons = this.sdpTree.find("span[stype='icon']");
  735. for (var tm0 = 0; tm0 < tmIcons.length; tm0++) { $(tmIcons[tm0]).css("display", tmDisplay); };
  736. },
  737.  
  738. // @ method: setShowSelectBox() 设置树节点选择按钮显示与否
  739. // @ depict:设置树节点是否显示选择按钮(复选框或单选框)
  740. // @ params: [string] checkType 显示按钮类型:空、radio、checkbox
  741. // @ pbtype: 外部调用方法
  742. setShowSelectBox: function (checkType) {
  743. if (!checkType) { checkType = ""; };
  744. if (checkType == "checkbox") {
  745. this.options.selecttype = "checkbox";
  746. } else if (checkType == "radio") {
  747. this.options.selecttype = "radio";
  748. } else {
  749. this.options.selecttype = "";
  750. };
  751.  
  752. var tmCheckNodes = null;
  753. if (this.options.selecttype) {
  754. tmCheckNodes = this.sdpTree.find("span[stype='check']");
  755. if (tmCheckNodes.length > 0) { tmCheckNodes.remove(); };
  756. tmCheckNodes = this.sdpTree.find("span[stype='node']");
  757. for (var tm0 = 0; tm0 < tmCheckNodes.length; tm0++) {
  758. var tm_TitleNode = $(tmCheckNodes[tm0]).find("span[stype='text']");
  759. var tm_NodeID = tm_TitleNode.attr("id").replace(this.myFnId + "_sdptree_node_text_", "");
  760. if (this.options.selecttype == "checkbox") {
  761. $(tm_TitleNode).before('<span class="checkbox" stype="check" id="' + this.myFnId + '_sdptree_node_chk_' + tm_NodeID + '" ></span>');
  762. } else {
  763. $(tm_TitleNode).before('<span class="radiobtn" stype="check" id="' + this.myFnId + '_sdptree_node_chk_' + tm_NodeID + '" ></span>');
  764. };
  765. };
  766.  
  767. } else {
  768. tmCheckNodes = this.sdpTree.find("span[stype='check']");
  769. if (tmCheckNodes.length > 0) { tmCheckNodes.remove(); };
  770. }
  771. },
  772.  
  773. // @ method: checkedAll() 全部选中
  774. // @ depict: 当树开始复选时,实现选中全部树节点
  775. // @ pbtype: 外部调用方法
  776. checkedAll: function () {
  777. var _chkIcon = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_chk_" + this.options.rootcode);
  778. if ((_chkIcon) && _chkIcon.length > 0) {
  779. this._methods._checkedNodes(_chkIcon, true, true);
  780. }
  781. },
  782.  
  783. // @ method: unCheckAll() 取消选择
  784. // @ depict: 当树开始复选时,实现取消全部全部树节点的选中
  785. // @ pbtype: 外部调用方法
  786. uncheckAll: function () {
  787. var _chkIcon = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_chk_" + this.options.rootcode);
  788. if ((_chkIcon) && _chkIcon.length > 0) {
  789. this._methods._checkedNodes(_chkIcon, false, true);
  790. }
  791. },
  792.  
  793. // @ method: setOneNodeChecked() 设置节点选中与否 注意:此方法只设置此单个的节点
  794. // @ depict: 根据节点编码来设置节点选择与否 只设置一个节点,下级不进行设置
  795. // @ params: [string] nodeCode 节点编码
  796. // @ params: [bool] boolChecked 是否选中 说明:true 表示显示 false 表示不显示
  797. // @ pbtype: 外部调用方法
  798. setOneNodeChecked: function (nodeCode, boolChecked) {
  799. var boolVal = (boolChecked) ? true : false;
  800. var chkImg = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_chk_" + nodeCode);
  801. if ((chkImg) && chkImg.length > 0) {
  802. if (boolVal == chkImg.prop("checked")) { return; };
  803. if (this.options.selecttype == "radio") {
  804. if (boolVal) {
  805. var rdoAllIcon = this.sdpTree.find("span[stype='check']");
  806. for (var _tt = 0; _tt < rdoAllIcon.length; _tt++) {
  807. var _curRadio = $(rdoAllIcon[_tt]);
  808. if (_curRadio.prop("checked")) {
  809. _curRadio.prop("checked", false).removeClass("radiobtn").removeClass("radiobtn_check").addClass("radiobtn");
  810. };
  811. };
  812. chkImg.prop("checked", true).removeClass("radiobtn").removeClass("radiobtn_check").addClass("radiobtn_check");
  813. } else {
  814. chkImg.prop("checked", false).removeClass("radiobtn").removeClass("radiobtn_check").addClass("radiobtn");
  815. }
  816. } else if (this.options.selecttype == "checkbox") {
  817. chkImg.removeClass("checkbox").removeClass("checkbox_check").addClass(((boolVal) ? "checkbox_check" : "checkbox")).prop("checked", boolVal);
  818. };
  819. };
  820. },
  821.  
  822. // @ method: setNodeChecked() 设置节点选中与否 注意:此方法会自动设置下级(根据级联选择的原则)
  823. // @ depict: 根据节点编码来设置节点选择与否
  824. // @ params: [string] nodeCode 节点编码
  825. // @ params: [bool] boolValue 是否选中 说明:true 表示显示 false 表示不显示
  826. // @ pbtype: 外部调用方法
  827. setNodeChecked: function (nodeCode, boolValue) {
  828. var boolVal = (boolValue) ? true : false;
  829. var chkImg = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_chk_" + nodeCode);
  830. if ((chkImg) && chkImg.length > 0) {
  831. if (this.options.selecttype == "radio") {
  832. if (boolVal == chkImg.prop("checked")) { return; };
  833. if (boolVal) {
  834. var rdoAllIcon = this.sdpTree.find("span[stype='check']");
  835. for (var _tt = 0; _tt < rdoAllIcon.length; _tt++) {
  836. var _curRadio = $(rdoAllIcon[_tt]);
  837. if (_curRadio.prop("checked")) {
  838. _curRadio.prop("checked", false).removeClass("radiobtn").removeClass("radiobtn_check").addClass("radiobtn");
  839. };
  840. };
  841. chkImg.prop("checked", true).removeClass("radiobtn").removeClass("radiobtn_check").addClass("radiobtn_check");
  842. } else {
  843. chkImg.prop("checked", false).removeClass("radiobtn").removeClass("radiobtn_check").addClass("radiobtn");
  844. }
  845. } else if (this.options.selecttype == "checkbox") {
  846. this._methods._checkedNodes(chkImg, boolVal);
  847. };
  848. };
  849. },
  850.  
  851. // @ method: setNodeText() 设置节点文本值
  852. // @ depict:设置树节点内容文本标题
  853. // @ params: nodeCode string 节点编码
  854. // @ params: nodeText string 节点文本标题字符
  855. // @ pbtype: 外部调用方法
  856. setNodeText: function (nodeCode, nodeText) {
  857. var txtNode = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_text_" + nodeCode);
  858. if (txtNode.length > 0) {
  859. if ($.isNull(nodeText)) { nodeText = ""; };
  860. txtNode.text(nodeText);
  861. if (nodeCode == this.options.rootcode) {
  862. this.options.roottext = nodeText;
  863. } else {
  864. this._methods._hsNodes[nodeCode].nodetext = nodeText;
  865. };
  866. };
  867. },
  868.  
  869. // @ method: getNodeChecked() 获取节点是否选中
  870. // @ depict:获取节点是否选中
  871. // @ params: [string] nodeCode 节点编码
  872. // @ return: [bool] isChecked 返回是否选中(布尔:true/false)
  873. // @ pbtype: 外部调用方法
  874. getNodeChecked: function (nodeCode) {
  875. var isChecked = false;
  876. var chkImg = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_chk_" + nodeCode);
  877. if ((chkImg) && chkImg.length > 0) {
  878. isChecked = chkImg.prop("checked");
  879. } else {
  880. var tgNd = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_span_" + tgNodeCode);
  881. if ((tgNd) && tgNd.length > 0) {
  882. isChecked = tgNd.hasClass("node_select");
  883. }
  884. };
  885. return isChecked;
  886. },
  887.  
  888. // @ method: getCheckedNodes_Array() 获取选中节点的数组 to Array()
  889. // @ depict:获取树所有选中的节点 返回 Array 数组
  890. // @ return: Array 数组 每项根式 item [
  891. // @ (1、nodecode 节点编码),
  892. // @ (2、nodename 节点文本),
  893. // @ (3、nodesupcode 上级编码)
  894. // @ (4、nodelevel 节点级别)
  895. // @ ]
  896. // @ pbtype: 外部调用方法
  897. getCheckedNodes_Array: function () {
  898. var chkNodeList = this.sdpTree.find("span[stype='check']");
  899. var retArray = new Array();
  900. var retCode = "", retText = "", retSupCode = "", retLevel = -1; curIcon = null;
  901. for (var tm1 = 0; tm1 < chkNodeList.length; tm1++) {
  902. curIcon = $(chkNodeList[tm1]);
  903. if (!curIcon.prop("checked")) { continue; };
  904. retCode = curIcon.attr("id").replace(this.myFnId + "_sdptree_node_chk_", "");
  905. if (this.options.rootcode == retCode) { continue; };
  906. retText = curIcon.parent().text();
  907. retSupCode = this._methods._hsNodes[retCode].supnodecode;
  908. retLevel = this._methods._hsNodes[retCode]._nodeLevel;
  909. retArray[retArray.length] = [retCode, retText, retSupCode, retLevel];
  910. };
  911. return retArray;
  912. },
  913.  
  914. // @ method: getCheckedNodes_String() 获取选中节点的字符串
  915. // @ depict:获取树所有选中的节点 返回 string 字符串(拼接字符串)
  916. // @ return:String 中的每项之间用小写的分号隔开
  917. // @ 每项顺序:nodecode(节点编码),nodename(节点文本),nodesupcode(上级编码),nodelevel(节点级别);
  918. // @ pbtype: 外部调用方法
  919. getCheckedNodes_String: function () {
  920. var chkNodeList = this.sdpTree.find("span[stype='check']");
  921. var retString = [], curIcon = null;
  922. var retCode = "", retText = "", retSupCode = "", retLevel = "-1";
  923. for (var tm1 = 0; tm1 < chkNodeList.length; tm1++) {
  924. curIcon = $(chkNodeList[tm1]);
  925. if (!curIcon.prop("checked")) { continue; };
  926. retCode = curIcon.attr("id").replace(this.myFnId + "_sdptree_node_chk_", "");
  927. if (this.options.rootcode == retCode) { continue; };
  928. retText = curIcon.parent().text();
  929. retSupCode = this._methods._hsNodes[retCode].supnodecode;
  930. retLevel = this._methods._hsNodes[retCode]._nodeLevel;
  931. retString.push(retCode + "," + retText + "," + retSupCode + "," + retLevel + ";");
  932. };
  933. return retString.join("");
  934. },
  935.  
  936. // @ method: getCheckedNodes_JsonObj() 获取选中节点的JSON数组
  937. // @ depict:获取树所有选中的节点 返回 Json 对象数组
  938. // @ return: JSON 对象数组
  939. // @ 每项 item{
  940. // @ nodecode: "节点编码",
  941. // @ nodename: "节点文本",
  942. // @ supnodecode: "上级编码",
  943. // @ nodelevel:节点级别
  944. // @ }
  945. // @ pbtype: 外部调用方法
  946. getCheckedNodes_JsonObj: function () {
  947. var chkNodeList = this.sdpTree.find("span[stype='check']");
  948. var retJson = new Array();
  949. var retCode = "", retText = "", retSupCode = "", retLevel = 0, curIcon = null;
  950. for (var tm1 = 0; tm1 < chkNodeList.length; tm1++) {
  951. curIcon = $(chkNodeList[tm1]);
  952. if (!curIcon.prop("checked")) { continue; };
  953. retCode = curIcon.attr("id").replace(this.myFnId + "_sdptree_node_chk_", "");
  954. if (this.options.rootcode == retCode) { continue; };
  955. retText = curIcon.parent().text();
  956. retSupCode = this._methods._hsNodes[retCode].supnodecode;
  957. retLevel = this._methods._hsNodes[retCode]._nodeLevel;
  958. var newItem = {
  959. nodecode: retCode,
  960. nodetext: retText,
  961. supnodecode: retSupCode,
  962. nodelevel: retLevel
  963. };
  964. retJson.push(newItem);
  965. };
  966. return retJson;
  967. },
  968.  
  969. // @ method: getCheckedNodes_XmlStr() 获取树所有选中的节点XML字符串
  970. // @ depict:获取树所有选中的节点生成固定格式的XML字符串
  971. // @ return: XML字符串
  972. // @ 每项 <row>
  973. // @ <nodecode><![CDATA[节点编码]]></nodecode>
  974. // @ <nodetext><![CDATA[节点文本]]></nodetext>
  975. // @ <supnodecode><![CDATA[上级编码]]></supnodecode>
  976. // @ <nodelevel><![CDATA[节点级别]]></nodelevel>
  977. // @ </row>
  978. // @ pbtype: 外部调用方法
  979. getCheckedNodes_XmlStr: function () {
  980. var chkNodeList = this.sdpTree.find("span[stype='check']");
  981. var retXml = ["<root>"];
  982. var retCode = "", retText = "", retSupCode = "", retLevel = 0, curIcon = null;
  983. for (var tm1 = 0; tm1 < chkNodeList.length; tm1++) {
  984. curIcon = $(chkNodeList[tm1]);
  985. if (!curIcon.prop("checked")) { continue; };
  986. retCode = curIcon.attr("id").replace(this.myFnId + "_sdptree_node_chk_", "");
  987. if (this.options.rootcode == retCode) { continue; };
  988. retText = curIcon.parent().text();
  989. retSupCode = this._methods._hsNodes[retCode].supnodecode;
  990. retLevel = this._methods._hsNodes[retCode]._nodeLevel;
  991. retXml.push("<row><nodecode><![CDATA[" + retCode + "]]></nodecode><nodetext><![CDATA[" + retText + "]]></nodetext><supnodecode><![CDATA[" + retSupCode + "]]></supnodecode><nodelevel><![CDATA[" + retLevel + "]]></nodelevel></row>");
  992. };
  993. retXml.push("</root>");
  994. return retXml.join("");
  995. },
  996.  
  997. // @ method: getCheckedNodes_Hash() 获取树所有选中的节点HASH数组
  998. // @ depict:获取树所有选中的节点 返回Hash 数组
  999. // @ return: Hash 中的每项:Hash.add(key=nodeID,value=nodeText);
  1000. // @ item[key:nodeID] = value:nodeText
  1001. // @ 根据key: hash[key] 获取返回值:value
  1002. // @ pbtype: 外部调用方法
  1003. getCheckedNodes_Hash: function () {
  1004. var chkNodeList = this.sdpTree.find("span[stype='check']");
  1005. var retHash = $.Hashtable();
  1006. var retCode = "", retText = "", curIcon = null;
  1007. for (var tm1 = 0; tm1 < chkNodeList.length; tm1++) {
  1008. curIcon = $(chkNodeList[tm1]);
  1009. if (!curIcon.prop("checked")) { continue; };
  1010. retCode = curIcon.attr("id").replace(this.myFnId + "_sdptree_node_chk_", "");
  1011. if (this.options.rootcode == retCode) { continue; };
  1012. retText = curIcon.parent().text();
  1013. retHash.add(retCode, retText);
  1014. };
  1015. return retHash;
  1016. },
  1017.  
  1018. // @ method: getAllNodes_Hash() 获取树所有节点HASH数组
  1019. // @ depict:获取树所有节点HASH数组 返回Hash 数组
  1020. // @ return: Hash 中的每项:Hash.add(key=nodeID,value=nodeText);
  1021. // @ item[key:nodeID] = value:nodeText
  1022. // @ 根据key: hash[key] 获取返回值:value
  1023. // @ pbtype: 外部调用方法
  1024. getAllNodes_Hash: function () {
  1025. return this._methods._hsNodes;
  1026. },
  1027.  
  1028. // @ method: getAllNodes_Array() 获取树所有节点Array数组[分级的]
  1029. // @ depict:获取树所有节点 返回 Array 数组
  1030. // @ pbtype: 外部调用方法
  1031. getAllNodes_Array: function () {
  1032. return this._methods._dtNodes;
  1033. },
  1034.  
  1035. // @ method: expandNode() 展开所有节点
  1036. // @ depict: 展开目录树的所有节点
  1037. // @ pbtype: 外部调用方法
  1038. expandAll: function () {
  1039. for (var tm0 = 0; tm0 < this._methods._dtNodes.length; tm0++) {
  1040. var tm_ExpNode = this._methods._dtNodes[tm0];
  1041. if (tm_ExpNode._haveChild) {
  1042. this.expandNode(tm_ExpNode.nodecode);
  1043. this.expandAllChilds(tm_ExpNode.nodecode);
  1044. };
  1045. };
  1046. },
  1047.  
  1048. // @ method: expandAllChilds() 展开指定节点的所有子节点
  1049. // @ depict: 展开目录树的中执行节点下的所有子节点
  1050. // @ params: nodeCode string 节点编码
  1051. // @ pbtype: 外部调用方法
  1052. expandAllChilds: function (nodeCode) {
  1053. var tsNode = this._methods._hsNodes[nodeCode];
  1054. if (tsNode._haveChild) {
  1055. for (var tm2 = 0; tm2 < tsNode._childs.length; tm2++) {
  1056. var subNode = tsNode._childs[tm2];
  1057. if (subNode._haveChild) {
  1058. this.expandNode(subNode.nodecode);
  1059. this.expandAllChilds(subNode.nodecode);
  1060. };
  1061. };
  1062. };
  1063. },
  1064.  
  1065. // @ method: expandNode() 展开指定的节点
  1066. // @ depict: 根据节点编码 执行展开此节点
  1067. // @ params: nodeCode string 节点编码
  1068. // @ pbtype: 外部调用方法
  1069. expandNode: function (nodeCode) {
  1070. var $plusImg = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_plus_" + nodeCode);
  1071. var $clipDiv = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_clip_" + nodeCode);
  1072. var $nodeIcn = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_icon_" + nodeCode);
  1073. if ($plusImg.length > 0) {
  1074. if ($plusImg.hasClass("node_plug_0n")) {
  1075. if (!$plusImg.hasClass("node_expd_0n")) { $plusImg.addClass("node_expd_0n").prop("open", true); };
  1076. } else if ($plusImg.hasClass("node_plug_1l")) {
  1077. if (!$plusImg.hasClass("node_expd_1l")) { $plusImg.addClass("node_expd_1l").prop("open", true); };
  1078. } else if ($plusImg.hasClass("node_plug_2b")) {
  1079. if (!$plusImg.hasClass("node_expd_2b")) { $plusImg.addClass("node_expd_2b").prop("open", true); };
  1080. } else if ($plusImg.hasClass("node_plug_2t")) {
  1081. if (!$plusImg.hasClass("node_expd_2t")) { $plusImg.addClass("node_expd_2t").prop("open", true); };
  1082. } else if ($plusImg.hasClass("node_plug_3a")) {
  1083. if (!$plusImg.hasClass("node_expd_3a")) { $plusImg.addClass("node_expd_3a").prop("open", true); };
  1084. };
  1085. };
  1086.  
  1087. if ($clipDiv.length > 0) { $clipDiv.css("display", "block"); };
  1088. if ($nodeIcn.length > 0) {
  1089. if ($nodeIcn.hasClass("custom_img")) {
  1090. var icnBgImg = ($nodeIcn.attr("expdimg")) ? $nodeIcn.attr("expdimg") : $nodeIcn.attr("collimg");
  1091. $nodeIcn.css("background-image", "url(" + icnBgImg + ")");
  1092. } else {
  1093. if (($nodeIcn.hasClass("folder_collapse")) && (!$nodeIcn.hasClass("folder_expand"))) { $nodeIcn.addClass("folder_expand"); };
  1094. }
  1095. };
  1096. },
  1097.  
  1098. // @ method: collapseAll() 收缩所有节点
  1099. // @ depict: 收缩目录树的所有节点
  1100. // @ pbtype: 外部调用方法
  1101. collapseAll: function () {
  1102. for (var tm0 = 0; tm0 < this._methods._dtNodes.length; tm0++) {
  1103. var tm_CollNode = this._methods._dtNodes[tm0];
  1104. if (tm_CollNode._haveChild) {
  1105. this.collapseNode(tm_CollNode.nodecode);
  1106. this.collapseAllChilds(tm_CollNode.nodecode);
  1107. };
  1108. };
  1109. },
  1110.  
  1111. // @ method: collapseAllChilds() 收缩指定节点的所有子节点
  1112. // @ depict: 收缩目录树的中执行节点下的所有子节点
  1113. // @ params: nodeCode string 节点编码
  1114. // @ pbtype: 外部调用方法
  1115. collapseAllChilds: function (nodeCode) {
  1116. var tsNode = this._methods._hsNodes[nodeCode];
  1117. if (tsNode._haveChild) {
  1118. for (var tm2 = 0; tm2 < tsNode._childs.length; tm2++) {
  1119. var subNode = tsNode._childs[tm2];
  1120. if (subNode._haveChild) {
  1121. this.collapseNode(subNode.nodecode);
  1122. this.collapseAllChilds(subNode.nodecode);
  1123. };
  1124. };
  1125. };
  1126. },
  1127.  
  1128. // @ method: collapseNode() 收缩指定的节点
  1129. // @ depict: 根据节点编码收缩此节点
  1130. // @ params: nodeCode string 节点编码
  1131. // @ pbtype: 外部调用方法
  1132. collapseNode: function (nodeCode) {
  1133. var $plusImg = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_plus_" + nodeCode);
  1134. var $clipDiv = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_clip_" + nodeCode);
  1135. var $nodeIcn = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_icon_" + nodeCode);
  1136. if ($plusImg.length > 0) {
  1137. if ($plusImg.hasClass("node_plug_0n")) {
  1138. if ($plusImg.hasClass("node_expd_0n")) { $plusImg.removeClass("node_expd_0n").prop("open", false); };
  1139. } else if ($plusImg.hasClass("node_plug_1l")) {
  1140. if ($plusImg.hasClass("node_expd_1l")) { $plusImg.removeClass("node_expd_1l").prop("open", false); };
  1141. } else if ($plusImg.hasClass("node_plug_2b")) {
  1142. if ($plusImg.hasClass("node_expd_2b")) { $plusImg.removeClass("node_expd_2b").prop("open", false); };
  1143. } else if ($plusImg.hasClass("node_plug_2t")) {
  1144. if ($plusImg.hasClass("node_expd_2t")) { $plusImg.removeClass("node_expd_2t").prop("open", false); };
  1145. } else if ($plusImg.hasClass("node_plug_3a")) {
  1146. if ($plusImg.hasClass("node_expd_3a")) { $plusImg.removeClass("node_expd_3a").prop("open", false); };
  1147. };
  1148. };
  1149. if ($clipDiv.length > 0) { $clipDiv.css("display", "none"); };
  1150. if ($nodeIcn.length > 0) {
  1151. if ($nodeIcn.hasClass("custom_img")) {
  1152. var icnBgImg = ($nodeIcn.attr("collimg")) ? $nodeIcn.attr("collimg") : $nodeIcn.attr("expdimg");
  1153. $nodeIcn.css("background-image", "url(" + icnBgImg + ")");
  1154. } else {
  1155. if (($nodeIcn.hasClass("folder_collapse")) && ($nodeIcn.hasClass("folder_expand"))) {
  1156. $nodeIcn.removeClass("folder_expand");
  1157. }
  1158. }
  1159. };
  1160. },
  1161.  
  1162. // @ method: expandLevel() 展开目录树中某层次所有节点
  1163. // @ depict: 根据节点层次级别
  1164. // @ params: levelNum [number] 节点层次级别[注意级别是从1开始,根目录属于0级]
  1165. // @ pbtype: 外部调用方法
  1166. expandLevel: function (levelNum) {
  1167. levelNum = parseInt(levelNum, 10);
  1168. if (isNaN(levelNum)) { return; };
  1169. var _treeNodesHash = this._methods._hsNodes;
  1170. for (var ll = 1; ll <= levelNum; ll++) {
  1171. for (var ndCode in _treeNodesHash) {
  1172. if (_treeNodesHash.hasOwnProperty(ndCode)) {
  1173. var ndItem = _treeNodesHash[ndCode];
  1174. if (ndItem._nodeLevel == ll) {
  1175. this.expandNode(ndItem.nodecode);
  1176. }
  1177. }
  1178. };
  1179. };
  1180. },
  1181.  
  1182. // @ method: collapseLevel() 收缩目录树中某层次所有节点
  1183. // @ depict: 根据节点层次级别
  1184. // @ params: levelNum [number] 节点层次级别[注意级别是从1开始,根目录属于0级]
  1185. // @ pbtype: 外部调用方法
  1186. collapseLevel: function (levelNum) {
  1187. levelNum = parseInt(levelNum, 10);
  1188. if (isNaN(levelNum)) { return; };
  1189.  
  1190. var _treeNodesHash = this._methods._hsNodes;
  1191. for (var ndCode in _treeNodesHash) {
  1192. if (_treeNodesHash.hasOwnProperty(ndCode)) {
  1193. var ndItem = _treeNodesHash[ndCode];
  1194. if (ndItem._nodeLevel == levelNum) {
  1195. this.collapseNode(ndItem.nodecode); // 收缩指定的节点
  1196. }
  1197. }
  1198. };
  1199. },
  1200.  
  1201. // @ method: getObject() 获取控件JQUERY 对象
  1202. // @ depict: 获取插件所对应的DOM 控件 JQUERY 对象
  1203. // @ return: [object] 返回控件JQUERY 对象 空为null
  1204. // @ pbtype: 外部调用方法
  1205. getObject: function () {
  1206. return this.myObject;
  1207. },
  1208.  
  1209. // @ method: getID() 获取控件ID
  1210. // @ depict: 获取此插件对应的控件ID属性值
  1211. // @ return: [string] 控件ID
  1212. // @ pbtype: 外部调用方法
  1213. getID: function () {
  1214. var _thisID = null;
  1215. if (this.myObject != null) { _thisID = this.myObject.attr("id"); };
  1216. if ($.isNull(_thisID) == true) { _thisID = null; };
  1217. return _thisID;
  1218. },
  1219.  
  1220. // @ method: getSdpID() 获取控件内嵌 ID
  1221. // @ depict: 获取此插件对应的控件SDP ID属性值
  1222. // @ pbtype: 外部调用方法
  1223. getSdpID: function () {
  1224. var _thisSdpID = null;
  1225. if (this.myObject != null) { _thisSdpID = this.myObject.attr("sdpid"); };
  1226. if ($.isNull(_thisSdpID) == true) { _thisSdpID = null; };
  1227. return _thisSdpID;
  1228. },
  1229.  
  1230. // @ method: onLocked() 锁定控件
  1231. // @ depict: 执行控件的锁定
  1232. // @ pbtype: 外部调用方法
  1233. onLocked: function () {
  1234. if (this.myObject == null) { return; };
  1235. if (this.getLocked() == false) {
  1236. this.myObject.attr("sdplocked", "yes");
  1237. }
  1238. },
  1239.  
  1240. // @ method: onUnLock() 解锁控件
  1241. // @ depict: 执行控件的锁定
  1242. // @ pbtype: 外部调用方法
  1243. onUnLock: function () {
  1244. if (this.myObject == null) { return; };
  1245. if (this.getLocked() == true) {
  1246. this.myObject.attr("sdplocked", "no");
  1247. }
  1248. },
  1249.  
  1250. // @ method: getLocked() 获取控件是否锁定
  1251. // @ depict: 获取控件的锁定状态
  1252. // @ return: [bool] 控件锁定状态 true false
  1253. // @ pbtype: 外部调用方法
  1254. getLocked: function () {
  1255. if (this.myObject) {
  1256. return (this.myObject.attr("sdplocked") == "yes");
  1257. } else {
  1258. return false;
  1259. }
  1260. },
  1261.  
  1262. // @ method: getVisible() 获取控件是否可见
  1263. // @ depict: 获取控件的可见状态(显示/隐藏)
  1264. // @ return: [bool] 控件锁定状态 true: 表示显示(可见); false:表示隐藏(不可见)
  1265. // @ pbtype: 外部调用方法
  1266. getVisible: function () {
  1267. if (this.myObject != null) {
  1268. return this.myObject.is(":hidden");
  1269. } else {
  1270. return true;
  1271. }
  1272. },
  1273.  
  1274. // @ method: onRefresh() 树刷新
  1275. // @ depict: 目录树刷新[当前树是通过自动加载的时,即从SQL中获取有效]
  1276. // @ pbtype: 外部调用方法
  1277. onRefresh: function () {
  1278. var P = this.options;
  1279. this.focusNodeCode = "";
  1280. },
  1281.  
  1282. // @ method: _loadParam() 加载控件Option参数
  1283. // @ depict: 加载控件在设计器中Option参数
  1284. // @ pbtype: 内部调用方法
  1285. _loadParam: function () {
  1286. this.options = $.extend({}, this.defaults); // 合并参数
  1287. },
  1288.  
  1289. // @ method: _bindEvent() 事件绑定
  1290. // @ depict: 执行控件 样式、事件等绑定
  1291. // @ pbtype: 内部调用方法
  1292. _bindEvent: function () {
  1293. if (!this.myContainer) { return; };
  1294. var _this = this;
  1295. this.myContainer.click(function (event) {
  1296. _this._onClickHandle(event);
  1297. }).dblclick(function (event) {
  1298. _this._onDblClickHandle(event);
  1299. }).contextmenu(function (event) {
  1300. return false;
  1301. });
  1302. },
  1303.  
  1304. // @ method: _onClickHandle() 节点单击事件处理
  1305. // @ depict: 对目录树节点的单击事件处理
  1306. // @ params: [object] event 当前目标对象(DOM)
  1307. // @ pbtype: 内部调用方法
  1308. _onClickHandle: function (event) {
  1309. var e = window.event || event;
  1310. e = e.srcElement || e.target;
  1311. if (e.tagName.toLowerCase() != "span") { return; };
  1312. var tgObj = $(e);
  1313. var tgNodeCode = null, tgNd = null;
  1314. switch (tgObj.attr("stype")) {
  1315. case "text":
  1316. tgNodeCode = tgObj.attr("id").replace(this.myFnId + "_sdptree_node_text_", "");
  1317. tgNd = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_span_" + tgNodeCode);
  1318. if (!tgNd.hasClass("node_select")) {
  1319. tgNd.addClass("node_select");
  1320. var forFocus = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_span_" + this.focusNodeCode);
  1321. if (forFocus.length > 0) { forFocus.removeClass("node_select"); };
  1322. this.focusNodeCode = tgNodeCode;
  1323. };
  1324. this._onNodeClick(tgNd);
  1325. break;
  1326. case "plus":
  1327. tgNodeCode = tgObj.attr("id").replace(this.myFnId + "_sdptree_node_plus_", "");
  1328. if (typeof (tgObj.prop("open")) == "undefined") {
  1329. if (tgObj.hasClass("node_plug_0n")) {
  1330. if (tgObj.hasClass("node_expd_0n")) { tgObj.prop("open", true); } else { tgObj.prop("open", false); };
  1331. } else if (tgObj.hasClass("node_plug_1l")) {
  1332. if (tgObj.hasClass("node_expd_1l")) { tgObj.prop("open", true); } else { tgObj.prop("open", false); };
  1333. } else if (tgObj.hasClass("node_plug_2b")) {
  1334. if (tgObj.hasClass("node_expd_2b")) { tgObj.prop("open", true); } else { tgObj.prop("open", false); };
  1335. } else if (tgObj.hasClass("node_plug_2t")) {
  1336. if (tgObj.hasClass("node_expd_2t")) { tgObj.prop("open", true); } else { tgObj.prop("open", false); };
  1337. } else if (tgObj.hasClass("node_plug_3a")) {
  1338. if (tgObj.hasClass("node_expd_3a")) { tgObj.prop("open", true); } else { tgObj.prop("open", false); };
  1339. };
  1340. };
  1341. if (tgObj.prop("open")) { this.collapseNode(tgNodeCode); } else { this.expandNode(tgNodeCode); };
  1342. break;
  1343. case "check":
  1344. if (this.getLocked() == true) { return; };
  1345. tgNodeCode = tgObj.attr("id").replace(this.myFnId + "_sdptree_node_chk_", "");
  1346. tgNd = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_span_" + tgNodeCode);
  1347. var _oldCheckState = tgObj.prop("checked") || false;
  1348. this.setNodeChecked(tgNodeCode, !tgObj.prop("checked"));
  1349. var _newCheckState = tgObj.prop("checked") || false;
  1350. if (_oldCheckState != _newCheckState) { this._onNodeCheckedChange(tgNd); };
  1351. break;
  1352. };
  1353. },
  1354.  
  1355. // @ method: _onDblClickHandle() 节点双击事件处理
  1356. // @ depict: 对目录树节点的双击事件处理
  1357. // @ params: [object] event 当前目标对象(DOM)
  1358. // @ pbtype: 内部调用方法
  1359. _onDblClickHandle: function (event) { // 节点双击事件
  1360. var e = event || window.event;
  1361. e = e.srcElement || e.target;
  1362. if (e.tagName.toLowerCase() != "span") { return; };
  1363. var dblOBJ = $(e);
  1364. if (dblOBJ.attr("stype") == "text") {
  1365. var dblNodeCode = dblOBJ.attr("id").replace(this.myFnId + "_sdptree_node_text_", "");
  1366. var plusOBJ = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_plus_" + dblNodeCode);
  1367. var tgNd = this.sdpTree.find("#" + this.myFnId + "_sdptree_node_span_" + dblNodeCode);
  1368. if (plusOBJ.length > 0) {
  1369. if (typeof (plusOBJ.prop("open")) == "undefined") {
  1370. if (plusOBJ.hasClass("node_plug_0n")) {
  1371. if (plusOBJ.hasClass("node_expd_0n")) { plusOBJ.prop("open", true); } else { plusOBJ.prop("open", false); };
  1372. } else if (plusOBJ.hasClass("node_plug_1l")) {
  1373. if (plusOBJ.hasClass("node_expd_1l")) { plusOBJ.prop("open", true); } else { plusOBJ.prop("open", false); };
  1374. } else if (plusOBJ.hasClass("node_plug_2b")) {
  1375. if (plusOBJ.hasClass("node_expd_2b")) { plusOBJ.prop("open", true); } else { plusOBJ.prop("open", false); };
  1376. } else if (plusOBJ.hasClass("node_plug_2t")) {
  1377. if (plusOBJ.hasClass("node_expd_2t")) { plusOBJ.prop("open", true); } else { plusOBJ.prop("open", false); };
  1378. } else if (plusOBJ.hasClass("node_plug_3a")) {
  1379. if (plusOBJ.hasClass("node_expd_3a")) { plusOBJ.prop("open", true); } else { plusOBJ.prop("open", false); };
  1380. };
  1381. };
  1382. if (plusOBJ.prop("open")) {
  1383. this.collapseNode(dblNodeCode);
  1384. }
  1385. else { this.expandNode(dblNodeCode); };
  1386. };
  1387. this._onNodeDblClick(tgNd);
  1388. };
  1389. },
  1390.  
  1391. // @ method: _onNodeClick() 执行节点自定单击事件
  1392. // @ depict: 执行节点自定单击事件
  1393. // @ params: [object] node 树节点DOM对象
  1394. // @ pbtype: 内部调用方法
  1395. _onNodeClick: function (node) {
  1396. if (!node) { return; };
  1397. var nodeClickEvent = this.options.nodeclick;
  1398. if (typeof (nodeClickEvent) != 'function') { nodeClickEvent = $.strToFunction(nodeClickEvent); };
  1399. if (typeof (nodeClickEvent) == 'function') {
  1400. try {
  1401. var ndCode = $(node).attr("id").replace(this.myFnId + "_sdptree_node_span_", "");
  1402. var ndItem = new this.nodeItem();
  1403. if (ndCode == this.options.rootcode) {
  1404. ndItem.nodecode = this.options.rootcode;
  1405. ndItem.nodetext = this.options.roottext;
  1406. ndItem.nodeurl = this.options.rooturl;
  1407. ndItem.iconcollapse = this.options.rooticon;
  1408. } else {
  1409. ndItem = this._methods._hsNodes[ndCode];
  1410. };
  1411.  
  1412. var eParams = {
  1413. treePlug: this,
  1414. nodeObject: $(node)[0],
  1415. nodeParams: ndItem
  1416. };
  1417. nodeClickEvent.call(null, eParams);
  1418. } catch (error) {
  1419. alert("控件单击事件执行错误!" + error);
  1420. }
  1421. };
  1422. },
  1423.  
  1424. // @ method: _onNodeDblClick() 执行节点自定双击事件
  1425. // @ depict: 执行节点自定双击事件
  1426. // @ params: [object] node 树节点DOM对象
  1427. // @ pbtype: 内部调用方法
  1428. _onNodeDblClick: function (node) {
  1429. if (!node) { return; };
  1430. var nodeDblClickEvent = this.options.nodedblclick;
  1431. if (typeof (nodeDblClickEvent) != 'function') { nodeDblClickEvent = $.strToFunction(nodeDblClickEvent); };
  1432. if (typeof (nodeDblClickEvent) == 'function') {
  1433. try {
  1434. var ndCode = $(node).attr("id").replace(this.myFnId + "_sdptree_node_span_", "");
  1435. var ndItem = new this.nodeItem();
  1436. if (ndCode == this.options.rootcode) {
  1437. ndItem.nodecode = this.options.rootcode;
  1438. ndItem.nodetext = this.options.roottext;
  1439. ndItem.nodeurl = this.options.rooturl;
  1440. ndItem.iconcollapse = this.options.rooticon;
  1441. } else {
  1442. ndItem = this._methods._hsNodes[ndCode];
  1443. };
  1444. var eParams = {
  1445. treePlug: this,
  1446. nodeObject: $(node)[0],
  1447. nodeParams: ndItem
  1448. };
  1449. nodeDblClickEvent.call(null, eParams);
  1450. } catch (error) {
  1451. alert("控件双击事件执行错误!" + error);
  1452. }
  1453. };
  1454. },
  1455.  
  1456. // @ method: _onNodeCheckedChange() 执行节点自定选择(选中状态)改变事件
  1457. // @ depict: 执行节点自定选择(选中状态)改变事件
  1458. // @ params: [object] node 树节点DOM对象
  1459. // @ pbtype: 内部调用方法
  1460. _onNodeCheckedChange: function (node) {
  1461. if (!node) { return; };
  1462. var nodeCheckedChange = this.options.checkedchange;
  1463. if (typeof (nodeCheckedChange) != 'function') { nodeCheckedChange = $.strToFunction(nodeCheckedChange); };
  1464. if (typeof (nodeCheckedChange) == 'function') {
  1465. try {
  1466. var ndCode = $(node).attr("id").replace(this.myFnId + "_sdptree_node_span_", "");
  1467. var ndItem = new this.nodeItem();
  1468. if (ndCode == this.options.rootcode) {
  1469. ndItem.nodecode = this.options.rootcode;
  1470. ndItem.nodetext = this.options.roottext;
  1471. ndItem.nodeurl = this.options.rooturl;
  1472. ndItem.iconcollapse = this.options.rooticon;
  1473. } else {
  1474. ndItem = this._methods._hsNodes[ndCode];
  1475. };
  1476. var eParams = {
  1477. treePlug: this,
  1478. nodeObject: $(node)[0],
  1479. nodeParams: ndItem
  1480. };
  1481. nodeCheckedChange.call(null, eParams);
  1482. } catch (error) {
  1483. alert("控件双击事件执行错误!" + error);
  1484. }
  1485. };
  1486. },
  1487.  
  1488. _methods: {
  1489. _fnObject: null,
  1490. _myObject: null,
  1491. _myContainer: null,
  1492. _myFnId: "",
  1493. _sdpTree: null,
  1494. _myNodes: [],
  1495. _hsNodes: null,
  1496. _dtNodes: null,
  1497. _createTree: function () { // 创建树HTML对象
  1498. // 初始化变量参数
  1499. this._sdpTree.empty(); // 清空目录树内的所有内容
  1500. this._fnObject.focusNodeCode = "";
  1501. this._myNodes = [];
  1502. this._hsNodes = new $.Hashtable();
  1503. this._dtNodes = [];
  1504. var _tmNodes = [], F = this._fnObject, P = this._fnObject.options, _this = this;
  1505.  
  1506. // 重组目录节点(依次将所有的节点组成自己的树) 一次循环完成 提高效率
  1507. function Renew_GroupNodes(currNodes) {
  1508. // 重绘节点上下级关系
  1509. function Renew_Tree(reNode) {
  1510. if (_tmNodes[reNode.nodecode]) {
  1511. for (var n = 0; n < _tmNodes[reNode.nodecode].length; n++) {
  1512. reNode._childs[n] = _tmNodes[reNode.nodecode][n];
  1513. reNode._childs[n]._parent = reNode;
  1514. reNode._childs[n]._firstFlag = (n == 0) ? true : false;
  1515. reNode._childs[n]._lastFlag = (n == (_tmNodes[reNode.nodecode].length - 1)) ? true : false;
  1516. reNode._childs[n]._haveChild = (_tmNodes[_tmNodes[reNode.nodecode][n].nodecode]) ? true : false;
  1517. reNode._childs[n]._nodeLevel = reNode._nodeLevel + 1;
  1518. Renew_Tree(_tmNodes[reNode.nodecode][n]); // 迭代循环
  1519. }
  1520. }
  1521. };
  1522.  
  1523. var m = 0;
  1524. _tmNodes[P.rootcode] = []; // 根节点
  1525. for (m = 0; m < currNodes.length; m++) {
  1526. var _nd = currNodes[m];
  1527. _tmNodes[_nd.supnodecode] = _tmNodes[_nd.supnodecode] || [];
  1528. _tmNodes[_nd.supnodecode].push(_nd);
  1529. _this._hsNodes.add(_nd.nodecode, _nd);
  1530. };
  1531. var _rtNodes = _tmNodes[P.rootcode];
  1532.  
  1533. for (m = 0; m < _rtNodes.length; m++) {
  1534. _this._dtNodes[m] = _rtNodes[m];
  1535. _this._dtNodes[m]._parent = null;
  1536. _this._dtNodes[m]._firstFlag = (m == 0) ? true : false; // 设置参数
  1537. _this._dtNodes[m]._lastFlag = (m == (_rtNodes.length - 1)) ? true : false;
  1538. _this._dtNodes[m]._haveChild = (_tmNodes[_rtNodes[m].nodecode]) ? true : false;
  1539. _this._dtNodes[m]._nodeLevel = 1;
  1540. Renew_Tree(_rtNodes[m]); // 迭代循环
  1541. };
  1542.  
  1543. _rtNodes = null;
  1544. _tmNodes = null;
  1545. };
  1546.  
  1547. // 执行节点重组
  1548. Renew_GroupNodes(F.curNodes);
  1549. F.curNodes = []; // 清空临时节点数组变量,便于后续重新加载使用
  1550.  
  1551. // 定义前缀字符
  1552. var full_Prefix = this._myFnId + "_sdptree_node_full"; // 完整的一个节点DIV(包含:连线、+号图片、节点图片、选择框、节点文本)
  1553. var node_Prefix = this._myFnId + "_sdptree_node_span"; // 节点SPAN
  1554. // var plus_Prefix = this._myFnId + "_sdptree_node_plus"; // + 号图片
  1555. var nimg_Prefix = this._myFnId + "_sdptree_node_icon"; // 节点图片
  1556. var chkr_Prefix = this._myFnId + "_sdptree_node_chk"; // 选择图片
  1557. var text_Prefix = this._myFnId + "_sdptree_node_text"; // 节点文本
  1558. var clip_Prefix = this._myFnId + "_sdptree_node_clip"; // 子节点DIV
  1559.  
  1560. // 注意点:前台传入的所有自定义的图标,全部已经是指定的完整路径了,所以这里就不需要转换
  1561. var _rootCode = P.rootcode;
  1562. if (P.showroot) { // 判定是否显示根节点
  1563. var tmRhtml = [];
  1564. tmRhtml.push('<div id="' + full_Prefix + '_' + _rootCode + '" stype="full" >');
  1565. tmRhtml.push('<span id="' + node_Prefix + '_' + _rootCode + '" class="node_default" stype="node" >');
  1566. if (P.showicon) {
  1567. tmRhtml.push('<span id="' + nimg_Prefix + '_' + _rootCode + '" stype="icon" ');
  1568. if (P.rooticon) { // 是否客户自定义的图片
  1569. tmRhtml.push('class="custom_img" style="background-image: url(' + (P.rooticon) + ');"');
  1570. } else { // 启用默认的样式图片
  1571. tmRhtml.push('class="root_img"');
  1572. };
  1573. tmRhtml.push(' ></span>');
  1574. };
  1575. if (P.selecttype == "checkbox") { // 是否开启选择按钮
  1576. tmRhtml.push('<span id="' + chkr_Prefix + '_' + _rootCode + '" stype="check" class="checkbox"></span>');
  1577. } else if (P.selecttype == "radio") {
  1578. tmRhtml.push('<span id="' + chkr_Prefix + '_' + _rootCode + '" stype="check" class="radiobtn"></span>');
  1579. };
  1580. tmRhtml.push('<span id="' + text_Prefix + '_' + _rootCode + '" class="root_title" stype="text">' + P.roottext + '</span>');
  1581. tmRhtml.push('</span>');
  1582. tmRhtml.push('</div>');
  1583. this._sdpTree.append($(tmRhtml.join("")));
  1584. tmRhtml = null;
  1585. };
  1586. var $clipDom = null;
  1587. if (P.showroot) $clipDom = $('<div id="' + clip_Prefix + '_' + _rootCode + '" class="clipdiv" stype="clip" style="display: block" ></div>');
  1588. var _recHTML = this._createNodes(this._dtNodes);
  1589. if (_recHTML) {
  1590. if ($clipDom) { $clipDom.append($(_recHTML)); this._sdpTree.append($clipDom); } else { this._sdpTree.append($(_recHTML)); };
  1591. } else {
  1592. if ($clipDom) { this._sdpTree.append($clipDom); };
  1593. };
  1594. _recHTML = null;
  1595.  
  1596. // 绑定事件
  1597. this._bindEvent();
  1598. if (P.openall) { F.expandAll(); };
  1599. },
  1600. _createNodes: function (crNodes) { // 创建节点HTML
  1601. var full_Prefix = this._myFnId + "_sdptree_node_full"; // 完整的一个节点DIV(包含:连线、+号图片、节点图片、选择框、节点文本)
  1602. var node_Prefix = this._myFnId + "_sdptree_node_span"; // 节点SPAN
  1603. var plus_Prefix = this._myFnId + "_sdptree_node_plus"; // + 号图片
  1604. var nimg_Prefix = this._myFnId + "_sdptree_node_icon"; // 节点图片
  1605. var chkr_Prefix = this._myFnId + "_sdptree_node_chk"; // 选择图片
  1606. var text_Prefix = this._myFnId + "_sdptree_node_text"; // 节点文本
  1607. var clip_Prefix = this._myFnId + "_sdptree_node_clip"; // 子节点DIV
  1608. var P = this._fnObject.options; // 参数变量
  1609.  
  1610. var tmHTML = [];
  1611. for (var m = 0; m < crNodes.length; m++) {
  1612. var crNode = crNodes[m];
  1613. tmHTML.push('<div id="' + full_Prefix + '_' + crNode.nodecode + '" stype="full" >');
  1614. var tmIndent = [];
  1615. var tmParent = crNode._parent;
  1616. var lv = crNode._nodeLevel;
  1617. while (lv > 1) { tmIndent[tmIndent.length] = tmParent; tmParent = tmParent._parent; lv--; };
  1618. for (lv = tmIndent.length - 1; lv >= 0; lv--) {
  1619. tmHTML.push('<span class="' + ((this._fnObject.options.showline == true) ? ((tmIndent[lv]._lastFlag == false) ? "node_line_10" : "nullimg") : "nullimg") + '" stype="line" ></span>');
  1620. };
  1621. tmIndent = null;
  1622. tmParent = null;
  1623. var tmNdCode = crNode.nodecode;
  1624. if (P.showline == true) { // 2、节点自身图标 + -
  1625. if (crNode._haveChild) {
  1626. if (crNode._nodeLevel == 1 && P.showroot == false && crNode._firstFlag == true) {
  1627. tmHTML.push('<span id="' + plus_Prefix + '_' + tmNdCode + '" stype="plus" class="' + ((crNode._lastFlag) ? "node_plug_1l" : "node_plug_2b") + '"></span>');
  1628. } else {
  1629. tmHTML.push('<span id="' + plus_Prefix + '_' + tmNdCode + '" stype="plus" class="' + ((crNode._lastFlag) ? "node_plug_2t" : "node_plug_3a") + '"></span>');
  1630. };
  1631. } else {
  1632. if (crNode._nodeLevel == 1 && P.showroot == false && crNode._firstFlag == true) {
  1633. tmHTML.push('<span class="' + ((crNode._lastFlag) ? "node_line_11" : "node_line_20") + '" stype="line" ></span>');
  1634. } else {
  1635. tmHTML.push('<span class="' + ((crNode._lastFlag) ? "node_line_21" : "node_line_3n") + '" stype="line" ></span>');
  1636. };
  1637. };
  1638.  
  1639. } else { // 不显示线
  1640. var tmPlusStr = "stype=\"plus\" id=" + plus_Prefix + "_" + tmNdCode;
  1641. var tmLineStr = "stype=\"line\"";
  1642. tmHTML.push('<span class="' + ((crNode._haveChild == true) ? "node_plug_0n" : "nullimg") + '" ' + ((crNode._haveChild == true) ? tmPlusStr : tmLineStr) + ' ></span>');
  1643. };
  1644. tmHTML.push('<span id="' + node_Prefix + '_' + tmNdCode + '" class="node_default" stype="node" >'); // 3、添加节点相关
  1645.  
  1646. // 节点小图标
  1647. if (P.showicon) {
  1648.  
  1649. // 节点图标 根据每个节点自身是否定义 如果没有定义,再从OPTIONS 参数中查询
  1650. var cur_CollapseIcon = ""; // iconexpand: "", iconcollapse: ""
  1651. var cur_ExpandIcon = "";
  1652. if ($.isNull(crNode.iconcollapse) == false) { // 判定节点收缩时显示的图标
  1653. cur_CollapseIcon = crNode.iconcollapse; // 默认显示图标[收缩]
  1654. cur_ExpandIcon = crNode.iconexpand; // 展开显示图标[展开]
  1655. } else {
  1656. if (crNode._haveChild == true) // 判定是否有子节点
  1657. {
  1658. if ($.isNull(P.middefticon) == false) {
  1659. cur_CollapseIcon = P.middefticon; // 中间节点收缩[整体自定]
  1660. cur_ExpandIcon = P.midexpdicon; // 中间节点展开[整体自定]
  1661. }
  1662. } else {
  1663. if ($.isNull(P.endnodeicon) == false) {
  1664. cur_CollapseIcon = P.endnodeicon; // 末级节点[整体自定]
  1665. cur_ExpandIcon = "";
  1666. }
  1667. }
  1668. };
  1669.  
  1670. // 节点图片
  1671. if ($.isNull(cur_CollapseIcon) == false) {
  1672. 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>');
  1673. } else {
  1674. tmHTML.push('<span class="' + ((crNode._haveChild == true) ? "folder_collapse" : "folder_last") + '" id="' + nimg_Prefix + '_' + tmNdCode + '" stype="icon"></span>');
  1675. };
  1676. };
  1677. if (P.selecttype == "checkbox") { // 允许添加选择按钮
  1678. tmHTML.push('<span id="' + chkr_Prefix + '_' + tmNdCode + '" stype="check" class="checkbox" ></span>');
  1679. } else if (P.selecttype == "radio") {
  1680. tmHTML.push('<span id="' + chkr_Prefix + '_' + tmNdCode + '" stype="check" class="radiobtn" ></span>');
  1681. };
  1682. tmHTML.push('<span id="' + text_Prefix + '_' + tmNdCode + '" class="node_title" stype="text">' + crNode.nodetext + '</span>'); // 节点名称
  1683. tmHTML.push('</span>');
  1684. tmHTML.push('</div>');
  1685. if (crNode._childs.length > 0) {
  1686. tmHTML.push('<div id="' + clip_Prefix + '_' + tmNdCode + '" class="clipdiv" stype="clip" style="display:none;" >'); // 第一级以下全部隐藏
  1687. tmHTML.push(this._createNodes(crNode._childs));
  1688. tmHTML.push('</div>');
  1689. };
  1690. };
  1691. return tmHTML.join("");
  1692. },
  1693. _updateNode: function (nodeCode) { // 更新节点显示样式
  1694. var tmNowNode = this._hsNodes[nodeCode]; // 当前节点的Node数据
  1695. if (!tmNowNode) { return; };
  1696.  
  1697. // 1、首先更新自己
  1698. var nowFullNode = $(this._fnObject.getNode(nodeCode)); // 完整的节点对象
  1699. var nowSpanNode = nowFullNode.find("#" + this._myFnId + "_sdptree_node_span_" + nodeCode); // 节点NODESPAN
  1700. var nowPlusSpan = nowSpanNode.prev(); // 节点Plus + - 图标
  1701. var nowIconSpan = nowFullNode.find("#" + this._myFnId + "_sdptree_node_icon_" + nodeCode); // 节点ICON 图标
  1702.  
  1703. var tmIndent = null, tmParent = null, lv = null, lineClass = "", tmI = 0;
  1704. if (!tmNowNode._haveChild) { // 无子节点
  1705. // (1)、更新Plus
  1706. nowPlusSpan.removeAttr("id").removeAttr("open").attr("stype", "line");
  1707. if (this._fnObject.options.showline == true) { // 显示连接线
  1708. var lineClassName = "";
  1709. if (tmNowNode._nodeLevel == 1 && this._fnObject.options.showroot == false && tmNowNode._firstFlag == true) {
  1710. lineClassName = (tmNowNode._lastFlag) ? "node_line_11" : "node_line_20";
  1711. } else {
  1712. lineClassName = (tmNowNode._lastFlag) ? "node_line_21" : "node_line_3n";
  1713. };
  1714. nowPlusSpan.attr("class", lineClassName); // 更新样式ClassName
  1715. } else { // 不显示连接线
  1716. nowPlusSpan.attr("class", "nullimg");
  1717. };
  1718. // (2)、更新Icon
  1719. if (nowIconSpan.length > 0) {
  1720. if (!nowIconSpan.hasClass("custom_img")) { nowIconSpan.attr("class", "folder_last"); };
  1721. };
  1722.  
  1723. // (3)、更新Line
  1724. tmIndent = [];
  1725. tmParent = tmNowNode._parent;
  1726. lv = tmNowNode._nodeLevel;
  1727. while (lv > 1) { tmIndent[tmIndent.length] = tmParent; tmParent = tmParent._parent; lv--; };
  1728. lineClass = "", tmI = 0;
  1729. for (lv = tmIndent.length - 1; lv >= 0; lv--) {
  1730. lineClass = ((this._fnObject.options.showline == true) ? ((tmIndent[lv]._lastFlag == false) ? "node_line_10" : "nullimg") : "nullimg");
  1731. $(nowFullNode[0].childNodes[tmI]).attr("class", lineClass);
  1732. tmI++;
  1733. };
  1734.  
  1735. tmIndent = null;
  1736. tmParent = null;
  1737. lineClass = null;
  1738. } else { // 有子节点
  1739. // (1)、更新Plus
  1740. var nowClipDiv = this._sdpTree.find("#" + this._myFnId + "_sdptree_node_clip_" + nodeCode);
  1741. var isOpen = (nowClipDiv.css("display") == "none") ? false : true;
  1742. nowPlusSpan.attr("id", this._myFnId + "_sdptree_node_plus_" + nodeCode).attr("stype", "plus");
  1743. if (isOpen) { nowPlusSpan.attr("open", true); } else { nowPlusSpan.attr("open", false); }; // 设置展开状态
  1744. if (this._fnObject.options.showline == true) { // 显示连接线
  1745. var plusClassName = "";
  1746. if (tmNowNode._nodeLevel == 1 && this._fnObject.options.showroot == false && tmNowNode._firstFlag == true) {
  1747. plusClassName = (tmNowNode._lastFlag) ? "node_plug_1l" : "node_plug_2b";
  1748. } else { plusClassName = (tmNowNode._lastFlag) ? "node_plug_2t" : "node_plug_3a"; };
  1749. nowPlusSpan.attr("class", plusClassName); // 设置Plus 收缩样式
  1750. if (isOpen) {
  1751. switch (plusClassName) {
  1752. case "node_plug_1l":
  1753. nowPlusSpan.addClass("node_expd_1l");
  1754. break;
  1755. case "node_plug_2b":
  1756. nowPlusSpan.addClass("node_expd_2b");
  1757. break;
  1758. case "node_plug_2t":
  1759. nowPlusSpan.addClass("node_expd_2t");
  1760. break;
  1761. case "node_plug_3a":
  1762. nowPlusSpan.addClass("node_expd_3a");
  1763. break;
  1764. };
  1765. };
  1766. } else { // 不显示连接线
  1767. nowPlusSpan.attr("class", "node_plug_0n"); // 设置Plus 收缩样式
  1768. if (isOpen) nowPlusSpan.addClass("node_expd_0n"); // 添加Plus 展开样式
  1769. };
  1770.  
  1771. // (2)、更新Icon
  1772. if (nowIconSpan.length > 0) {
  1773. if (!nowIconSpan.hasClass("custom_img")) {
  1774. nowIconSpan.attr("class", "folder_collapse"); // 设置Icon 收缩样式
  1775. if (isOpen) { // 添加Icon 展开样式
  1776. nowIconSpan.addClass("folder_expand");
  1777. };
  1778. };
  1779. };
  1780.  
  1781. // (3)、更新Line
  1782. tmIndent = [];
  1783. tmParent = tmNowNode._parent;
  1784. lv = tmNowNode._nodeLevel;
  1785. while (lv > 1) { tmIndent[tmIndent.length] = tmParent; tmParent = tmParent._parent; lv--; };
  1786. lineClass = "", tmI = 0;
  1787. for (lv = tmIndent.length - 1; lv >= 0; lv--) {
  1788. lineClass = ((this._fnObject.options.showline == true) ? ((tmIndent[lv]._lastFlag == false) ? "node_line_10" : "nullimg") : "nullimg");
  1789. $(nowFullNode[0].childNodes[tmI]).attr("class", lineClass);
  1790. tmI++;
  1791. };
  1792.  
  1793. tmIndent = null;
  1794. tmParent = null;
  1795. lineClass = null;
  1796. };
  1797.  
  1798. // 2、其次更新下级
  1799. if (tmNowNode._haveChild) {
  1800. for (var tm2 = 0; tm2 < tmNowNode._childs.length; tm2++) {
  1801. var tmSubNodeCode = tmNowNode._childs[tm2].nodecode;
  1802. this._updateNode(tmSubNodeCode); // 迭代循环更新子节点
  1803. };
  1804. };
  1805. },
  1806.  
  1807. // @ params: [bool] isOpAll 是否全部 说明:前面调用时候,根据情况 是否执行全部节点的标志(一般使用于全部选中、取消选择使用)
  1808. _checkedNodes: function (node, bool, isOpAll) { // 设置多节点选中状态
  1809. this._checkedNode(node, bool); // 设置当前节点
  1810. if (this._fnObject.options.cascade || isOpAll) { // 级联选择节点 或 前台必须要全部节点
  1811. var tm_Prefix = this._myFnId + "_sdptree_node_chk_";
  1812. var tm_NodeCode = node.attr("id").replace(tm_Prefix, "");
  1813. var tm_Flag = true;
  1814. if ((bool) && (tm_NodeCode != this._fnObject.options.rootcode)) {
  1815. var tm_pNodeCode = this._hsNodes[tm_NodeCode].supnodecode; // 设置上级勾选
  1816. while (tm_Flag) {
  1817. var pNode = this._sdpTree.find("#" + tm_Prefix + tm_pNodeCode);
  1818. if (tm_pNodeCode == this._fnObject.options.rootcode) {
  1819. if (!pNode.prop("checked")) { this._checkedNode(pNode, true); };
  1820. tm_Flag = false;
  1821. break;
  1822. } else {
  1823. if (!pNode.prop("checked")) { this._checkedNode(pNode, true); };
  1824. tm_pNodeCode = this._hsNodes[tm_pNodeCode].supnodecode;
  1825. };
  1826. };
  1827. };
  1828.  
  1829. // 设置下级勾选
  1830. var subNodes = null;
  1831. if (tm_NodeCode == this._fnObject.options.rootcode) { subNodes = this._dtNodes; } else { subNodes = this._hsNodes[tm_NodeCode]._childs; };
  1832. this._checkedSubNodes(subNodes, bool);
  1833. subNodes = null;
  1834. };
  1835. },
  1836. _checkedNode: function (node, bool) {
  1837. node.removeClass("checkbox").removeClass("checkbox_check").addClass(((bool) ? "checkbox_check" : "checkbox")).prop("checked", bool);
  1838. },
  1839. _checkedSubNodes: function (nodes, bool) {
  1840. if (!nodes) { return; };
  1841. for (var tm1 = 0; tm1 < nodes.length; tm1++) {
  1842. var tm_Node = this._sdpTree.find("#" + this._myFnId + "_sdptree_node_chk_" + nodes[tm1].nodecode);
  1843. if (tm_Node.length > 0) {
  1844. this._checkedNode(tm_Node, bool);
  1845. if (nodes[tm1]._childs) { this._checkedSubNodes(nodes[tm1]._childs, bool); };
  1846. };
  1847. };
  1848. },
  1849. _removeHashNodes: function (nodeCode) {
  1850. var rmNode = this._hsNodes[nodeCode];
  1851. if (!rmNode) { return; };
  1852. if (rmNode._haveChild) {
  1853. for (var tm2 = 0; tm2 < rmNode._childs.length; tm2++) {
  1854. this._removeHashNodes(rmNode._childs[tm2].nodecode);
  1855. };
  1856. };
  1857.  
  1858. this._hsNodes.remove(nodeCode);
  1859. },
  1860. _bindEvent: function () {
  1861. var this_myNodes = this._sdpTree.find("span[stype='node']");
  1862. var this_treeID = this._myFnId;
  1863. var this_rootNode = this._sdpTree.find("#" + this_treeID + "_sdptree_node_span_" + this._fnObject.options.rootcode);
  1864. var _this = this;
  1865.  
  1866. if (this_rootNode.length > 0) {
  1867. this_rootNode.hover(function () {
  1868. $(this).addClass("node_hover").attr("title", $.text(this));
  1869. }, function () {
  1870. $(this).removeClass("node_hover").attr("title", "");
  1871. });
  1872. };
  1873. if (this_myNodes.length == 0) { return; };
  1874. this_myNodes.hover(function () { // 性能比较 此方法直接绑定hover 比 $().each() 方法耗时少很多
  1875. var tmThisNode = _this._hsNodes[$(this).attr("id").replace(this_treeID + "_sdptree_node_span_", "")];
  1876. var tmTitle = "";
  1877. if (tmThisNode) { tmTitle = tmThisNode.nodetitle; };
  1878. if (!tmTitle) { tmTitle = $.text(this); };
  1879. $(this).addClass("node_hover").attr("title", tmTitle);
  1880. }, function () {
  1881. $(this).removeClass("node_hover").attr("title", "");
  1882. });
  1883. }
  1884. }
  1885. };
  1886. };
  1887. })(jQuery);

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

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <head>
  4. <title>树 Tree </title>
  5. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  6. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  7. <link href="css/tree.css" rel="stylesheet" type="text/css" />
  8. <script src="js/min-jquery-1.9.1.js" type="text/javascript"></script>
  9. <script src="js/basic.js" type="text/javascript"></script>
  10. <script src="js/tree_plug.js" type="text/javascript"></script>
  11. <script type="text/javascript">
  12.  
  13. var nodesJson = {};
  14. var nodesXml = "";
  15.  
  16. // 定义一个Tree插件实例对象变量
  17. var treePlug = null;
  18.  
  19. // 加载 Tree
  20. function onLoadTree() {
  21.  
  22. // 创建一个Tree插件实例
  23. treePlug = new $.fn.webTree();
  24.  
  25. // 初始化插件对象内部参数
  26. treePlug.init($("div.sdp-tree"));
  27.  
  28. var ndItem = null;
  29. for (var i = 10; i < 20; i++) {
  30.  
  31. // 第一级节点
  32. ndItem = {
  33. nodecode: String(i),
  34. nodetext: "第一节点" + i,
  35. nodetitle: "",
  36. supnodecode: ""
  37.  
  38. };
  39. treePlug.addNodeItem(ndItem);
  40.  
  41. // 第二级节点
  42. for (var j = 10; j < 20; j++) {
  43. ndItem = {
  44. nodecode: String(i) + String(j),
  45. nodetext: "第二节点" + String(i) + String(j),
  46. nodetitle: "",
  47. supnodecode: String(i)
  48. };
  49. treePlug.addNodeItem(ndItem);
  50.  
  51. // 第三级节点
  52. for (var k = 10; k < 20; k++) {
  53. var tmCode = String(i) + String(j) + String(k);
  54. ndItem = {
  55. nodecode: tmCode,
  56. nodetext: "第二节点" + tmCode,
  57. nodetitle: "",
  58. supnodecode: String(i) + String(j)
  59. };
  60. treePlug.addNodeItem(ndItem);
  61. }
  62. }
  63.  
  64. };
  65.  
  66. treePlug.makeTree();
  67.  
  68. }
  69.  
  70. </script>
  71. </head>
  72. <body>
  73. <div style="position: absolute; display: block; top: 10px; left: 50px;">
  74. <button onclick="onLoadTree()">
  75. 加载目录树</button>
  76. </div>
  77. <div class="sdp-tree" id="demo_tree" style="position: absolute; display: block; left: 50px;
  78. top: 50px; height: 500px; width: 400px;">
  79. </div>
  80. </body>
  81. </html>

第六:最终显示效果

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

  1. (function ($) {
  2. $.extend({
  3. replaceAll: function (str, s1, s2) {
  4. if (str) {
  5. return str.replace(new RegExp(s1, "gm"), s2)
  6. } else {
  7. return str
  8. }
  9. },
  10. Hashtable: function () {
  11. Hash = function () { };
  12. Hash.prototype = {
  13. constructor: Hash,
  14. add: function (oKey, oVal) {
  15. if (!this.hasOwnProperty(oKey)) {
  16. this[oKey] = oVal
  17. }
  18. },
  19. count: function () {
  20. var _count = 0;
  21. for (var iCount in this) {
  22. if (this.hasOwnProperty(iCount)) {
  23. _count++
  24. }
  25. };
  26. return _count
  27. },
  28. remove: function (oKey) {
  29. if (this.hasOwnProperty(oKey)) {
  30. delete this[oKey]
  31. }
  32. },
  33. update: function (oKey, oVal) {
  34. this[oKey] = oVal
  35. },
  36. has: function (oKey) {
  37. var type = typeof oKey;
  38. if (type === 'string' || type === 'number') {
  39. return this.hasOwnProperty(oKey)
  40. } else if (type === 'function' && this.some(oKey)) {
  41. return true
  42. };
  43. return false
  44. },
  45. clear: function () {
  46. for (var oKey in this) {
  47. if (this.hasOwnProperty(oKey)) {
  48. delete this[oKey]
  49. }
  50. }
  51. },
  52. isempty: function () {
  53. for (var oKey in this) {
  54. if (this.hasOwnProperty(oKey)) {
  55. return false
  56. }
  57. };
  58. return true
  59. },
  60. each: function (fn) {
  61. for (var oKey in this) {
  62. if (this.hasOwnProperty(oKey)) {
  63. fn.call(this, this[oKey], oKey, this)
  64. }
  65. }
  66. },
  67. map: function (fn) {
  68. var hash = new Hash;
  69. for (var oKey in this) {
  70. if (this.hasOwnProperty(oKey)) {
  71. hash.add(oKey, fn.call(this, this[oKey], oKey, this))
  72. }
  73. };
  74. return hash
  75. },
  76. join: function (split) {
  77. split = split !== undefined ? split : ',';
  78. var rst = [];
  79. this.each(function (oVal) {
  80. rst.push(oVal)
  81. });
  82. return rst.join(split)
  83. },
  84. every: function (fn) {
  85. for (var oKey in this) {
  86. if (this.hasOwnProperty(oKey)) {
  87. if (!fn.call(this, this[oKey], oKey, this)) {
  88. return false
  89. }
  90. }
  91. };
  92. return true
  93. },
  94. some: function (fn) {
  95. for (var oKey in this) {
  96. if (this.hasOwnProperty(oKey)) {
  97. if (fn.call(this, this[oKey], oKey, this)) {
  98. return true
  99. }
  100. }
  101. };
  102. return false
  103. },
  104. find: function (oKey) {
  105. var type = typeof oKey;
  106. if (type === 'string' || type === 'number' && this.has(oKey)) {
  107. return this[oKey]
  108. } else if (type === 'function') {
  109. for (var _oKey in this) {
  110. if (this.hasOwnProperty(_oKey) && oKey.call(this, this[_oKey], _oKey, this)) {
  111. return this[_oKey]
  112. }
  113. }
  114. };
  115. return null
  116. }
  117. };
  118. return new Hash()
  119. },
  120. isNull: function (objVal) {
  121. if (typeof (objVal) == "undefined" || objVal == null) {
  122. return true
  123. };
  124. if (typeof (objVal) == "number" || typeof (objVal) == "boolean") {
  125. return false
  126. };
  127. if (objVal == "") {
  128. return true
  129. };
  130. try {
  131. if (objVal.length == 0) {
  132. return true
  133. };
  134. var strComp = $.replaceAll(String(objVal), " ", "");
  135. if (strComp == "" || strComp == "&nbsp;" || strComp.length == 0) {
  136. return true
  137. } else {
  138. return false
  139. }
  140. } catch (error) {
  141. return false
  142. }
  143. },
  144. isNumber: function (obj) {
  145. return (!isNaN(obj) && typeof (obj) == "number")
  146. },
  147. newGuid: function () {
  148. function S4() {
  149. return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
  150. };
  151. return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4()).toUpperCase()
  152. },
  153. loadXmlFile: function (xmlFilePath) {
  154. var retXmlDoc = null;
  155. if (xmlFilePath) {
  156. $.ajax({
  157. type: 'GET',
  158. async: false,
  159. url: xmlFilePath,
  160. dataType: 'xml',
  161. success: function (xmlData) {
  162. retXmlDoc = xmlData
  163. }
  164. })
  165. };
  166. return retXmlDoc
  167. },
  168. loadXmlString: function (xmlStr) {
  169. var retXmlDoc = null;
  170. if (xmlStr) {
  171. try {
  172. retXmlDoc = $.parseXML(xmlStr)
  173. } catch (g) {
  174. retXmlDoc = null
  175. }
  176. };
  177. return retXmlDoc
  178. },
  179. stopBubble: function (event) {
  180. event = event || window.event;
  181. $.preventDefault(event);
  182. $.stopPropagation(event);
  183. return false
  184. },
  185. preventDefault: function (event) {
  186. event = event || window.event;
  187. if (event.preventDefault) {
  188. event.preventDefault()
  189. };
  190. event.returnValue = false
  191. },
  192. stopPropagation: function (event) {
  193. event = event || window.event;
  194. if (event.stopPropagation) {
  195. event.stopPropagation()
  196. };
  197. event.cancelBubble = true
  198. },
  199. runStrEvent: function (strEvent, e) {
  200. var retEventValue = null;
  201. if (!strEvent) {
  202. return retEventValue
  203. };
  204. var _runEvent = $.strToFunction(strEvent);
  205. if (typeof (_runEvent) == 'function') {
  206. try {
  207. retEventValue = _runEvent.call(null, e)
  208. } catch (err) {
  209. retEventValue = err
  210. }
  211. } else {
  212. alert("错误:事件方法有误!" + strEvent);
  213. retEventValue = "ERROR:事件方法有误!"
  214. };
  215. if (typeof (retEventValue) == 'undefined') {
  216. retEventValue = null
  217. };
  218. return retEventValue
  219. },
  220. strToFunction: function (strEvent) {
  221. if (typeof (strEvent) == "function") {
  222. return strEvent
  223. } else if (!strEvent || typeof (strEvent) != "string") {
  224. return null
  225. } else {
  226. try {
  227. strEvent = $.trim(String(strEvent));
  228. if (strEvent.indexOf('(') > 0) {
  229. strEvent = strEvent.substring(0, strEvent.indexOf('('))
  230. };
  231. return (new Function("return " + strEvent))()
  232. } catch (error) {
  233. return null
  234. }
  235. }
  236. },
  237. getJSON_FromFile: function (filePath) {
  238. var jsonObj = null;
  239. if (filePath) {
  240. $.ajaxSettings.async = false;
  241. $.getJSON(filePath,
  242. function (retData) {
  243. jsonObj = retData
  244. });
  245. $.ajaxSettings.async = true
  246. };
  247. return jsonObj
  248. },
  249. getJSON_FromStr: function (jsonStr) {
  250. var jsonObj = null;
  251. if (jsonStr) {
  252. try {
  253. jsonObj = $.parseJSON(jsonStr)
  254. } catch (error) {
  255. jsonObj = null
  256. }
  257. };
  258. return jsonObj
  259. }
  260.  
  261. });
  262. })(jQuery);

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

JS--插件: 树Tree 开发与实现的更多相关文章

  1. JQuery 树状结构 jQuery-treeview.js 插件

    由简入繁实现Jquery树状结构 在项目中,我们经常会需要一些树状结构的样式来显示层级结构等,比如下图的样式,之前在学.net的时候可以直接拖个服务端控件过来直接使用非常方便.但是利用Jquery的一 ...

  2. js插件---Bootstrap 树控件

    js插件---Bootstrap 树控件 一.总结 一句话总结:可以直接用gojs,或者搜索js,jquery的树控件,或者bootstrap树控件,一大堆 gojs 二.JS组件系列——Bootst ...

  3. 前端开发需要了解的JS插件

    excanvas.js/Chart.js/cubism.js/d3.js/dc.js/dx.chartjs.js/echarts.js/flot.js 用途:构建数据统计图表,兼容多浏览器 jquer ...

  4. js插件---tree(多级文件)插件如何使用

    js插件---tree(多级文件)插件如何使用 一.总结 一句话总结:还是一般的引入js和css后js调用的方式, 只不过tree调用的时候必须设置一个 HTML 模板(就是调用的那段html代码,别 ...

  5. js插件ztree使用

    最新给公司后台写了一个配置页面,在网上搜到一个js插件ztree,记录一下使用心得. 首先说一下ztree官网,好多方法我都是从官网api上学习的,官网地址http://www.treejs.cn/v ...

  6. js无限级树菜单

    以前做网站,树形菜单一般都很简单,自己定义风格样式,简单的js控制,后来原来网上很多文章都在讨论Js树型菜单,看了几个实例,发现这个树比较简单好用. http://hovertree.com/texi ...

  7. jQuery.cookie.js插件了解及使用方法

    jquery.cookie.js插件实现浏览器的cookie存储,该插件是基于jquery开发,方便cookie使用. jquerycookie.js的下载地址 http://plugins.jque ...

  8. Intense Images – 全屏浏览图像的 JS 插件

    Intense Images 是一个独立的 JavaScript 库,用于查看全屏图像.使用触摸/鼠标来实现图片位置的平移.图像元素的所有样式都是可以自定义的,Intense.js 只处理图像浏览器和 ...

  9. 《Node.js+MongoDB+AngularJS Web开发》读书笔记及联想

    总体介绍 <Node.js+MongoDB+AngularJS Web开发>,于2015年6月出版,是一本翻译过来的书,原书名为<Node.js,MongoDB and Angula ...

随机推荐

  1. 201871010118-唐敬博《面向对象程序设计(java)》第十二周学习总结

    博文正文开头格式:(2分) 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.co ...

  2. navicat密码错误的问题

    上集说到我的navicat打不开对吧..‘ 这下就来聊聊打开了的问题 下午非常开心,就打开了mysql的图形化界面, 但是,在我连接数据库的时候就报错了 错误就是密码错误那行 什么什么‘localho ...

  3. js的call()方法

    // ① 当函数中没有this时,call().apply()和直接执行没有区别 function fn(){ console.log("aaa") } fn() // aaa f ...

  4. options模块介绍

    一. options是什么? 是tornado中为我们提供好的一个模块. 二. options的作用? 用来定义, 存储, 转换全局参数. 即定义变量 三. options如何使用? import t ...

  5. 【转】机器学习实战之K-Means算法

    一,引言 先说个K-means算法很高大上的用处,来开始新的算法学习.我们都知道每一届的美国总统大选,那叫一个竞争激烈.可以说,谁拿到了各个州尽可能多的选票,谁选举获胜的几率就会非常大.有人会说,这跟 ...

  6. MySQL实战45讲学习笔记:第十三讲

    一.引子 经常会有同学来问我,我的数据库占用空间太大,我把一个最大的表删掉了一半的数据,怎么表文件的大小还是没变? 那么今天,我就和你聊聊数据库表的空间回收,看看如何解决这个问题. 这里,我们还是针对 ...

  7. Node.js安装使用-VueCLI安装使用-工程化的Vue.js开发

    作者 | Jeskson 来源 | 达达前端小酒馆 搭建Node.js环境 什么是Node.js简介呢?它是一个基于JavaScript的运行环境,Node.js发布于2009年5月,对Chrome ...

  8. [LeetCode] 491. Increasing Subsequences 递增子序列

    Given an integer array, your task is to find all the different possible increasing subsequences of t ...

  9. [LeetCode] 370. Range Addition 范围相加

    Assume you have an array of length n initialized with all 0's and are given k update operations. Eac ...

  10. [LeetCode] 31. Next Permutation 下一个排列

    Implement next permutation, which rearranges numbers into the lexicographically next greater permuta ...