eleTree.js 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263
  1. /**
  2. * @Name: 基于layui的tree重写
  3. * @Author: 李祥
  4. * @License:MIT
  5. * 最近修改时间: 2019/03/06
  6. */
  7. layui.define(["jquery", "laytpl"], function (exports) {
  8. var $ = layui.jquery;
  9. var laytpl = layui.laytpl;
  10. var hint = layui.hint();
  11. var MOD_NAME = "eleTree";
  12. //外部接口
  13. var eleTree = {
  14. //事件监听
  15. on: function (events, callback) {
  16. return layui.onevent.call(this, MOD_NAME, events, callback);
  17. },
  18. render: function (options) {
  19. var inst = new Class(options);
  20. return thisTree.call(inst);
  21. }
  22. }
  23. var thisTree = function () {
  24. var _self = this;
  25. var options = _self.config;
  26. // 暴漏外面的方法
  27. return {
  28. // 接收两个参数,1. 节点 key 2. 节点数据的数组
  29. updateKeyChildren: function (key, data) {
  30. if (options.data.length === 0) return;
  31. return _self.updateKeyChildren.call(_self, key, data);
  32. },
  33. updateKeySelf: function (key, data) {
  34. if (options.data.length === 0) return;
  35. return _self.updateKeySelf.call(_self, key, data);
  36. },
  37. remove: function (key) {
  38. if (options.data.length === 0) return;
  39. return _self.remove.call(_self, key);
  40. },
  41. append: function (key, data) {
  42. if (options.data.length === 0) return;
  43. return _self.append.call(_self, key, data);
  44. },
  45. insertBefore: function (key, data) {
  46. if (options.data.length === 0) return;
  47. return _self.insertBefore.call(_self, key, data);
  48. },
  49. insertAfter: function (key, data) {
  50. if (options.data.length === 0) return;
  51. return _self.insertAfter.call(_self, key, data);
  52. },
  53. // 接收两个 boolean 类型的参数,1. 是否只是叶子节点,默认值为 false 2. 是否包含半选节点,默认值为 false
  54. getChecked: function (leafOnly, includeHalfChecked) {
  55. if (options.data.length === 0) return;
  56. return _self.getChecked.call(_self, leafOnly, includeHalfChecked);
  57. },
  58. // 接收勾选节点数据的数组
  59. setChecked: function (data, isReset) {
  60. if (options.data.length === 0) return;
  61. return _self.setChecked.call(_self, data, isReset);
  62. },
  63. // 取消选中
  64. unCheckNodes: function () {
  65. if (options.data.length === 0) return;
  66. return _self.unCheckNodes.call(_self);
  67. },
  68. unCheckArrNodes: function (data) {
  69. if (options.data.length === 0) return;
  70. return _self.unCheckArrNodes.call(_self, data);
  71. },
  72. expandAll: function () {
  73. options.elem.children(".eleTree-node").children(".eleTree-node-group").empty();
  74. _self.expandAll.call(_self, options.data, [], 1, true);
  75. _self.unCheckNodes(true);
  76. _self.defaultChecked();
  77. _self.checkboxInit();
  78. },
  79. unExpandAll: function () {
  80. return _self.unExpandAll.call(_self);
  81. },
  82. reload: function (options) {
  83. return _self.reload.call(_self, options);
  84. },
  85. search: function (value) {
  86. return _self.search.call(_self, value);
  87. }
  88. }
  89. }
  90. // 模板渲染
  91. var TPL_ELEM = function (options, floor, parentStatus) {
  92. return [
  93. '{{# for(var i=0;i<d.length;i++){ }}',
  94. '<div class="eleTree-node" data-' + options.request.key + '="{{d[i]["' + options.request.key + '"]}}" eletree-floor="' + floor + '" style="display: none;">',
  95. '<div class="eleTree-node-content" style="padding-left: ' + (options.indent * floor) + 'px;">',
  96. '<span class="eleTree-node-content-icon">',
  97. '<i class="layui-icon layui-icon-triangle-r ',
  98. function () {
  99. if (options.lazy) {
  100. var str = [
  101. '{{# if(!d[i]["' + options.request.isLeaf + '"]){ }}',
  102. 'lazy-icon" ></i>',
  103. '{{# }else{ }}',
  104. 'leaf-icon" style="color: transparent;" ></i>',
  105. '{{# } }}'
  106. ].join("");
  107. return str;
  108. }
  109. return ['{{# if(!d[i]["' + options.request.children + '"] || d[i]["' + options.request.children + '"].length===0){ }}',
  110. 'leaf-icon" style="color: transparent;"',
  111. '{{# } }}',
  112. '"></i>'
  113. ].join("");
  114. }(),
  115. '</span>',
  116. function () {
  117. if (options.showCheckbox) {
  118. var status = "";
  119. if (parentStatus === "1") {
  120. status = '"1" checked';
  121. } else if (parentStatus === "2") {
  122. status = '"2"';
  123. } else {
  124. status = '"0"';
  125. }
  126. return [
  127. '{{# if(d[i]["' + options.request.checked + '"]) { }}',
  128. '<input type="checkbox" name="eleTree-node" eleTree-status="1" checked data-checked class="eleTree-hideen ',
  129. '{{# }else{ }}',
  130. '<input type="checkbox" name="eleTree-node" eleTree-status=' + status + ' class="eleTree-hideen ',
  131. '{{# } }}',
  132. '{{# if(d[i]["' + options.request.disabled + '"]) { }}',
  133. 'eleTree-disabled',
  134. '{{# } }}',
  135. '" />'
  136. ].join("");
  137. }
  138. return ''
  139. }(),
  140. '<span class="eleTree-node-content-label">{{d[i]["' + options.request.name + '"]}}</span>',
  141. '</div>',
  142. '<div class="eleTree-node-group">',
  143. '</div>',
  144. '</div>',
  145. '{{# } }}'
  146. ].join("");
  147. }
  148. var TPL_NoText = function () {
  149. return '<h3 class="eleTree-noText" style="text-align: center;height: 30px;line-height: 30px;color: #888;">{{d.emptText}}</h3>';
  150. }
  151. var Class = function (options) {
  152. options.response = $.extend({}, this.config.response, options.response);
  153. options.request = $.extend({}, this.config.request, options.request);
  154. this.config = $.extend({}, this.config, options);
  155. this.prevClickEle = null;
  156. this.nameIndex = 1;
  157. this.render();
  158. };
  159. Class.prototype = {
  160. constructor: Class,
  161. config: {
  162. elem: "",
  163. data: [],
  164. emptText: "暂无数据", // 内容为空的时候展示的文本
  165. renderAfterExpand: true, // 是否在第一次展开某个树节点后才渲染其子节点
  166. highlightCurrent: false, // 是否高亮当前选中节点,默认值是 false。
  167. defaultExpandAll: false, // 是否默认展开所有节点
  168. expandOnClickNode: true, // 是否在点击节点的时候展开或者收缩节点, 默认值为 true,如果为 false,则只有点箭头图标的时候才会展开或者收缩节点。
  169. checkOnClickNode: false, // 是否在点击节点的时候选中节点,默认值为 false,即只有在点击复选框时才会选中节点。
  170. defaultExpandedKeys: [], // 默认展开的节点的 key 的数组
  171. autoExpandParent: true, // 展开子节点的时候是否自动展开父节点
  172. showCheckbox: false, // 节点是否可被选择
  173. checkStrictly: false, // 在显示复选框的情况下,是否严格的遵循父子不互相关联的做法,默认为 false
  174. defaultCheckedKeys: [], // 默认勾选的节点的 key 的数组
  175. accordion: false, // 是否每次只打开一个同级树节点展开(手风琴效果)
  176. indent: 16, // 相邻级节点间的水平缩进,单位为像素
  177. lazy: false, // 是否懒加载子节点,需与 load 方法结合使用
  178. load: function () {
  179. }, // 加载子树数据的方法,仅当 lazy 属性为true 时生效
  180. draggable: false, // 是否开启拖拽节点功能
  181. contextmenuList: [], // 启用右键菜单,支持的操作有:"copy","add","edit","remove"
  182. searchNodeMethod: null, // 对树节点进行筛选时执行的方法,返回 true 表示这个节点可以显示,返回 false 则表示这个节点会被隐藏
  183. method: "get",
  184. url: "",
  185. contentType: "",
  186. headers: {},
  187. done: null,
  188. response: {
  189. statusName: "code",
  190. statusCode: 0,
  191. dataName: "data"
  192. },
  193. request: {
  194. name: "label",
  195. key: "id",
  196. children: "children",
  197. disabled: "disabled",
  198. checked: "checked",
  199. isLeaf: "isLeaf"
  200. }
  201. },
  202. render: function () {
  203. if (this.config.indent > 30) {
  204. this.config.indent = 30;
  205. } else if (this.config.indent < 10) {
  206. this.config.indent = 10;
  207. }
  208. var options = this.config;
  209. options.where = options.where || {};
  210. if (!options.elem) return hint.error("缺少elem参数");
  211. options.elem = typeof options.elem === "string" ? $(options.elem) : options.elem;
  212. this.filter = options.elem.attr("lay-filter");
  213. // load加载框
  214. options.elem.append('<div class="eleTree-loadData"><i class="layui-icon layui-icon-loading layui-icon layui-anim layui-anim-rotate layui-anim-loop"></i></div>')
  215. // 判断加载方式
  216. if (options.data.length === 0) {
  217. this.ajaxGetData();
  218. } else {
  219. this.renderData();
  220. }
  221. },
  222. renderData: function () {
  223. var options = this.config;
  224. // 渲染第一层
  225. laytpl(TPL_ELEM(options, 0)).render(options.data, function (string) {
  226. options.elem.html(string).children().show();
  227. });
  228. // 懒加载 > 展开所有 > 初始展开项 > 初始渲染所有子节点 > 初始选中项 > 每次点击只渲染当前层(默认)
  229. // 判断所有dom是否全部加载
  230. if (!options.lazy) {
  231. if (!options.renderAfterExpand || options.defaultExpandAll || options.defaultExpandedKeys.length > 0 || options.defaultCheckedKeys.length > 0) {
  232. this.expandAll(options.data, [], 1);
  233. }
  234. }
  235. this.eleTreeEvent();
  236. this.checkboxRender();
  237. this.checkboxEvent();
  238. this.defaultChecked();
  239. this.nodeEvent();
  240. this.rightClickMenu();
  241. if (!options.checkStrictly) {
  242. this.checkboxInit();
  243. }
  244. },
  245. ajaxGetData: function () {
  246. var options = this.config;
  247. var _self = this;
  248. if (!options.url) {
  249. laytpl(TPL_NoText()).render(options, function (string) {
  250. options.elem.html(string);
  251. });
  252. return;
  253. }
  254. var data = $.extend({}, options.where);
  255. if (options.contentType && options.contentType.indexOf("application/json") == 0) { //提交 json 格式
  256. data = JSON.stringify(data);
  257. }
  258. $.ajax({
  259. type: options.method || 'get'
  260. , url: options.url
  261. , contentType: options.contentType
  262. , data: data
  263. , dataType: 'json'
  264. , headers: options.headers || {}
  265. , success: function (res) {
  266. if (res[options.response.statusName] != options.response.statusCode || !res[options.response.dataName]) {
  267. hint.error("请检查数据格式是否符合规范");
  268. typeof options.done === 'function' && options.done(res);
  269. return;
  270. }
  271. options.data = res[options.response.dataName];
  272. _self.renderData();
  273. typeof options.done === 'function' && options.done(res);
  274. }
  275. });
  276. },
  277. reload: function (options) {
  278. var _self = this;
  279. if (this.config.data && this.config.data.constructor === Array) this.config.data = [];
  280. this.config = $.extend({}, this.config, options);
  281. $(this.config.elem).off(); // 取消事件绑定,防止多次绑定事件
  282. // reload记录选中的数据
  283. // this.getChecked().forEach(function(val) {
  284. // if($.inArray(val.key,this.config.defaultCheckedKeys)===-1){
  285. // this.config.defaultCheckedKeys.push(val.key);
  286. // }
  287. // },this);
  288. return eleTree.render(this.config)
  289. },
  290. // 下拉
  291. eleTreeEvent: function () {
  292. var _self = this;
  293. var options = this.config;
  294. // 下拉
  295. var expandOnClickNode = options.expandOnClickNode ? ".eleTree-node-content" : ".eleTree-node-content>.eleTree-node-content-icon";
  296. options.elem.on("click", expandOnClickNode, function (e) {
  297. e.stopPropagation();
  298. var eleTreeNodeContent = $(this).parent(".eleTree-node").length === 0 ? $(this).parent(".eleTree-node-content") : $(this);
  299. var eleNode = eleTreeNodeContent.parent(".eleTree-node");
  300. var sibNode = eleTreeNodeContent.siblings(".eleTree-node-group");
  301. var el = eleTreeNodeContent.children(".eleTree-node-content-icon").children(".layui-icon");
  302. // 添加active背景
  303. if (_self.prevClickEle) _self.prevClickEle.removeClass("eleTree-node-content-active");
  304. if (options.highlightCurrent) eleTreeNodeContent.addClass("eleTree-node-content-active");
  305. _self.prevClickEle = eleTreeNodeContent;
  306. if (el.hasClass("icon-rotate")) {
  307. // 合并
  308. sibNode.children(".eleTree-node:not(.eleTree-search-hide)").hide("fast");
  309. el.removeClass("icon-rotate");
  310. return;
  311. }
  312. if (sibNode.children(".eleTree-node").length === 0) {
  313. var floor = Number(eleNode.attr("eletree-floor")) + 1;
  314. var data = _self.reInitData(eleNode);
  315. var d = data.currentData;
  316. // 是否懒加载
  317. if (options.lazy && el.hasClass("lazy-icon")) {
  318. el.removeClass("layui-icon-triangle-r").addClass("layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop");
  319. options.load(d, function (getData) {
  320. d[options.request.children] = getData;
  321. var eletreeStatus = eleTreeNodeContent.children("input.eleTree-hideen").attr("eletree-status");
  322. if (d[options.request.children] && d[options.request.children].length > 0) {
  323. laytpl(TPL_ELEM(options, floor, eletreeStatus)).render(d[options.request.children], function (string) {
  324. sibNode.append(string).children().show("fast");
  325. });
  326. } else {
  327. el.css("color", "transparent").addClass("leaf-icon");
  328. }
  329. el.removeClass("lazy-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop").addClass("layui-icon-triangle-r icon-rotate");
  330. _self.checkboxRender();
  331. // 懒加载子元素选择祖父(待写)
  332. })
  333. } else {
  334. var eletreeStatus = eleTreeNodeContent.children("input.eleTree-hideen").attr("eletree-status");
  335. d[options.request.children] && d[options.request.children].length > 0 && laytpl(TPL_ELEM(options, floor, eletreeStatus)).render(d[options.request.children], function (string) {
  336. sibNode.append(string);
  337. });
  338. // 选择祖父
  339. var eleNode1 = sibNode.children(".eleTree-node").eq(0);
  340. if (eleNode1.length === 0) {
  341. _self.checkboxRender();
  342. return;
  343. }
  344. var siblingNode1 = eleNode1.siblings(".eleTree-node");
  345. var item1 = eleNode1.children(".eleTree-node-content").children(".eleTree-hideen").get(0);
  346. _self.selectParents(item1, eleNode1, siblingNode1);
  347. _self.checkboxRender();
  348. }
  349. }
  350. // 显示隐藏没有搜索类的
  351. sibNode.children(".eleTree-node:not(.eleTree-search-hide)").show("fast");
  352. el.addClass("icon-rotate");
  353. // 手风琴效果
  354. if (options.accordion) {
  355. var node = eleTreeNodeContent.parent(".eleTree-node").siblings(".eleTree-node");
  356. node.children(".eleTree-node-group").children(".eleTree-node:not(.eleTree-search-hide)").hide("fast");
  357. node.children(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon").removeClass("icon-rotate");
  358. }
  359. })
  360. },
  361. // checkbox选中
  362. checkboxEvent: function () {
  363. var options = this.config;
  364. var _self = this;
  365. var checkOnClickNode = options.checkOnClickNode ? ".eleTree-node-content" : ".eleTree-checkbox";
  366. // input添加属性eleTree-status:即input的三种状态,"0":未选中,"1":选中,"2":子孙部分选中
  367. options.elem.on("click", checkOnClickNode, function (e, type) {
  368. e.stopPropagation();
  369. var eleTreeNodeContent = $(this).parent(".eleTree-node").length === 0 ? $(this).parent(".eleTree-node-content") : $(this);
  370. var checkbox = eleTreeNodeContent.children(".eleTree-checkbox");
  371. if (checkbox.hasClass("eleTree-checkbox-disabled")) return;
  372. // 获取点击所在数据
  373. var node = eleTreeNodeContent.parent(".eleTree-node");
  374. // var d=_self.reInitData(node).currentData;
  375. // 实际的input
  376. var inp = checkbox.siblings(".eleTree-hideen").get(0);
  377. var childNode = eleTreeNodeContent.siblings(".eleTree-node-group").find("input[name='eleTree-node']");
  378. // 添加active背景
  379. if (_self.prevClickEle) _self.prevClickEle.removeClass("eleTree-node-content-active");
  380. if (options.highlightCurrent) eleTreeNodeContent.addClass("eleTree-node-content-active");
  381. _self.prevClickEle = eleTreeNodeContent;
  382. if (!inp) {
  383. return;
  384. }
  385. if (inp.checked) {
  386. // 反选自身
  387. $(inp).prop("checked", false).attr("eleTree-status", "0");
  388. // 点击祖父层选中子孙层
  389. if (!options.checkStrictly) {
  390. childNode.prop("checked", false);
  391. childNode.attr("eleTree-status", "0");
  392. }
  393. } else {
  394. // 反选自身
  395. $(inp).prop("checked", true).attr("eleTree-status", "1");
  396. // 点击祖父层选中子孙层
  397. if (!options.checkStrictly) {
  398. childNode.prop("checked", true).attr("eleTree-status", "1");
  399. }
  400. }
  401. var eleNode = eleTreeNodeContent.parent(".eleTree-node");
  402. // 点击子孙层选中祖父层(递归)
  403. if (!options.checkStrictly) {
  404. var siblingNode = eleNode.siblings(".eleTree-node");
  405. // 点击子孙层选中祖父层(递归)
  406. _self.selectParents(inp, eleNode, siblingNode);
  407. }
  408. _self.checkboxRender();
  409. if (type === "default") return;
  410. layui.event.call(inp, MOD_NAME, 'nodeChecked(' + _self.filter + ')', {
  411. node: eleNode,
  412. data: _self.reInitData(eleNode),
  413. isChecked: inp.checked
  414. });
  415. })
  416. },
  417. // 对后台数据有 checked:true 的默认选中项渲染父子层
  418. checkboxInit: function () {
  419. var options = this.config;
  420. var _self = this;
  421. options.elem.find("input[data-checked]").each(function (index, item) {
  422. var checkboxEl = $(item).siblings(".eleTree-checkbox");
  423. var childNode = checkboxEl.parent(".eleTree-node-content").siblings(".eleTree-node-group").find("input[name='eleTree-node']");
  424. // 选择当前
  425. $(item).prop("checked", "checked").attr("eleTree-status", "1");
  426. checkboxEl.addClass("eleTree-checkbox-checked");
  427. checkboxEl.children("i").addClass("layui-icon-ok").removeClass("eleTree-checkbox-line");
  428. // 选择子孙
  429. childNode.prop("checked", "checked").attr("eleTree-status", "1");
  430. childNode.siblings(".eleTree-checkbox").addClass("eleTree-checkbox-checked");
  431. childNode.siblings(".eleTree-checkbox").children("i").addClass("layui-icon-ok").removeClass("eleTree-checkbox-line");
  432. // 选择祖父
  433. var eleNode = checkboxEl.parent(".eleTree-node-content").parent(".eleTree-node");
  434. var siblingNode = eleNode.siblings(".eleTree-node");
  435. _self.selectParents(item, eleNode, siblingNode);
  436. })
  437. _self.checkboxRender();
  438. },
  439. // 通过子元素选中祖父元素
  440. selectParents: function (inp, eleNode, siblingNode) {
  441. // inp: 实际input(dom元素)
  442. // eleNode: input父层类(.eleTree-node)
  443. // siblingNode: 父层同级兄弟
  444. while (Number(eleNode.attr("eletree-floor")) !== 0) {
  445. // 同级input状态存入数组
  446. var arr = [];
  447. arr.push($(inp).attr("eleTree-status"));
  448. siblingNode.each(function (index, item) {
  449. var siblingIsChecked = $(item).children(".eleTree-node-content").children("input[name='eleTree-node']").attr("eleTree-status");
  450. arr.push(siblingIsChecked);
  451. })
  452. // 父元素的实际input
  453. var parentInput = eleNode.parent(".eleTree-node-group").siblings(".eleTree-node-content").children("input[name='eleTree-node']");
  454. // 父元素的checkbox替代
  455. var parentCheckbox = parentInput.siblings(".eleTree-checkbox");
  456. // 子都选中则选中父
  457. if (arr.every(function (val) {
  458. return val === "1";
  459. })) {
  460. parentInput.prop("checked", true).attr("eleTree-status", "1");
  461. }
  462. // 子有一个未选中则checkbox第三种状态
  463. if (arr.some(function (val) {
  464. return val === "0" || val === "2";
  465. })) {
  466. parentInput.attr("eleTree-status", "2");
  467. }
  468. // 子全部未选中则取消父选中(并且取消第三种状态)
  469. if (arr.every(function (val) {
  470. return val === "0";
  471. })) {
  472. parentInput.prop("checked", false);
  473. parentInput.attr("eleTree-status", "0");
  474. }
  475. var parentNode = eleNode.parents("[eletree-floor='" + (Number(eleNode.attr("eletree-floor")) - 1) + "']");
  476. var parentCheckbox = parentNode.children(".eleTree-node-content").children("input[name='eleTree-node']").get(0);
  477. var parentSiblingNode = parentNode.siblings(".eleTree-node");
  478. eleNode = parentNode;
  479. inp = parentCheckbox;
  480. siblingNode = parentSiblingNode;
  481. }
  482. },
  483. // 初始展开所有
  484. expandAll: function (data, arr, floor, isMethodsExpandAll) {
  485. var options = this.config;
  486. var _self = this;
  487. data.forEach(function (val, index) {
  488. arr.push(index);
  489. if (val[options.request.children] && val[options.request.children].length > 0) {
  490. var el = options.elem.children(".eleTree-node").eq(arr[0]).children(".eleTree-node-group");
  491. for (var i = 1; i < arr.length; i++) {
  492. el = el.children(".eleTree-node").eq(arr[i]).children(".eleTree-node-group");
  493. }
  494. laytpl(TPL_ELEM(options, floor)).render(val[options.request.children], function (string) {
  495. el.append(string);
  496. // 判断是否展开所有
  497. if (options.defaultExpandAll || isMethodsExpandAll) {
  498. el.siblings(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon").addClass("icon-rotate");
  499. el.children().show();
  500. } else if (options.defaultExpandedKeys.length > 0) {
  501. // 继续展开祖父层
  502. var f = function (eleP) {
  503. if (options.autoExpandParent) {
  504. eleP.parents(".eleTree-node").each(function (i, item) {
  505. if ($(item).attr("data-" + options.request.key)) {
  506. $(item).children(".eleTree-node-group").siblings(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon").addClass("icon-rotate");
  507. $(item).children(".eleTree-node-group").children().show();
  508. }
  509. })
  510. }
  511. }
  512. // 展开指定id项
  513. var id = el.parent(".eleTree-node").attr("data-" + options.request.key);
  514. id = isNaN(id) ? id : Number(id);
  515. if ($.inArray(id, options.defaultExpandedKeys) !== -1) {
  516. // 直接展开子节点
  517. el.siblings(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon").addClass("icon-rotate");
  518. el.children().show();
  519. // 展开子项是否继续展开祖父项
  520. f(el.parent(".eleTree-node[data-" + options.request.key + "]"));
  521. } else {
  522. // 如当前节点的子节点有展开项,则展开当前子节点的祖父层
  523. el.children(".eleTree-node").each(function (index, item) {
  524. var id = $(item).attr("data-" + options.request.key);
  525. id = isNaN(id) ? id : Number(id);
  526. if ($.inArray(id, options.defaultExpandedKeys) !== -1) {
  527. f($(item));
  528. return false;
  529. }
  530. })
  531. }
  532. }
  533. });
  534. floor++;
  535. _self.expandAll(val[options.request.children], arr, floor, isMethodsExpandAll);
  536. floor--;
  537. }
  538. // 重置数组索引
  539. arr.pop();
  540. })
  541. },
  542. // 初始默认选中
  543. defaultChecked: function () {
  544. var options = this.config;
  545. if (options.defaultCheckedKeys.length === 0) {
  546. return false;
  547. }
  548. // 判断是否父子无关
  549. if (options.checkStrictly) {
  550. options.defaultCheckedKeys.forEach(function (val, index) {
  551. var nodeContent = options.elem.find("[data-" + options.request.key + "='" + val + "']").children(".eleTree-node-content");
  552. // 如果当前没选中则选中
  553. if (nodeContent.children(".eleTree-hideen").prop("checked") === false) {
  554. nodeContent.children(".eleTree-checkbox").trigger("click", ["default"]);
  555. }
  556. })
  557. return false;
  558. }
  559. // 父元素优先
  560. var arr = $.extend([], options.defaultCheckedKeys);
  561. options.defaultCheckedKeys.forEach(function (val, index) {
  562. options.elem.find("[data-" + options.request.key + "='" + val + "']").find("[data-" + options.request.key + "]").each(function (i, item) {
  563. var id = $(item).attr("data-" + options.request.key);
  564. id = isNaN(id) ? id : Number(id);
  565. var isInArrayIndex = $.inArray(id, arr);
  566. if (isInArrayIndex !== -1) {
  567. arr.splice(isInArrayIndex, 1);
  568. }
  569. })
  570. })
  571. arr.forEach(function (val, index) {
  572. var nodeContent = options.elem.find("[data-" + options.request.key + "='" + val + "']").children(".eleTree-node-content");
  573. // 如果当前没选中则选中
  574. if (nodeContent.children(".eleTree-hideen").prop("checked") === false) {
  575. nodeContent.children(".eleTree-checkbox").trigger("click", ["default"]);
  576. }
  577. })
  578. },
  579. // 自定义checkbox解析
  580. checkboxRender: function () {
  581. var options = this.config;
  582. options.elem.find(".eleTree-checkbox").remove();
  583. options.elem.find("input.eleTree-hideen[type=checkbox]").each(function (index, item) {
  584. if ($(item).hasClass("eleTree-disabled")) {
  585. $(item).after('<div class="eleTree-checkbox eleTree-checkbox-disabled"><i class="layui-icon"></i></div>');
  586. } else {
  587. $(item).after('<div class="eleTree-checkbox"><i class="layui-icon"></i></div>');
  588. }
  589. var checkbox = $(item).siblings(".eleTree-checkbox");
  590. if ($(item).attr("eletree-status") === "1") {
  591. checkbox.addClass("eleTree-checkbox-checked");
  592. checkbox.children("i").addClass("layui-icon-ok").removeClass("eleTree-checkbox-line");
  593. } else if ($(item).attr("eletree-status") === "0") {
  594. checkbox.removeClass("eleTree-checkbox-checked");
  595. checkbox.children("i").removeClass("layui-icon-ok eleTree-checkbox-line");
  596. } else if ($(item).attr("eletree-status") === "2") {
  597. checkbox.addClass("eleTree-checkbox-checked");
  598. checkbox.children("i").removeClass("layui-icon-ok").addClass("eleTree-checkbox-line");
  599. }
  600. })
  601. },
  602. // 通过dom节点找对应数据
  603. reInitData: function (node) {
  604. var options = this.config;
  605. var i = node.index();
  606. var floor = Number(node.attr("eletree-floor"));
  607. var arr = []; // 节点对应的index
  608. while (floor >= 0) {
  609. arr.push(i);
  610. floor = floor - 1;
  611. node = node.parents("[eletree-floor='" + floor + "']");
  612. i = node.index();
  613. }
  614. arr = arr.reverse();
  615. var oData = this.config.data;
  616. // 当前节点的父节点数据
  617. var parentData = oData[arr[0]];
  618. // 当前节点的data数据
  619. var d = oData[arr[0]];
  620. for (var i = 1; i < arr.length; i++) {
  621. d = d[options.request.children] ? d[options.request.children][arr[i]] : d;
  622. }
  623. for (var i = 1; i < arr.length - 1; i++) {
  624. parentData = parentData[options.request.children] ? parentData[options.request.children][arr[i]] : parentData;
  625. }
  626. return {
  627. currentData: d,
  628. parentData: {
  629. data: parentData,
  630. childIndex: arr[arr.length - 1]
  631. },
  632. index: arr
  633. }
  634. },
  635. // 通过key查找数据
  636. keySearchToOpera: function (key, callback) {
  637. var options = this.config;
  638. var _self = this;
  639. // 查找数据
  640. var fn = function (data) {
  641. var obj = {
  642. i: 0,
  643. len: data.length
  644. }
  645. for (; obj.i < obj.len; obj.i++) {
  646. if (data[obj.i][options.request.key] !== key) {
  647. if (data[obj.i][options.request.children] && data[obj.i][options.request.children].length > 0) {
  648. fn(data[obj.i][options.request.children]);
  649. }
  650. } else {
  651. callback(data, obj);
  652. }
  653. }
  654. }
  655. fn(options.data);
  656. },
  657. updateKeyChildren: function (key, data) {
  658. var options = this.config;
  659. var node = options.elem.find("[data-" + options.request.key + "='" + key + "']");
  660. var floor = Number(node.attr("eletree-floor")) + 1;
  661. var _self = this;
  662. this.keySearchToOpera(key, function (d, obj) {
  663. // 数据更新
  664. d[obj.i][options.request.children] = data;
  665. // dom更新
  666. node.length !== 0 && laytpl(TPL_ELEM(options, floor)).render(data, function (string) {
  667. $(node).children(".eleTree-node-group").empty().append(string);
  668. options.defaultExpandAll && $(node).children(".eleTree-node-group").children().show();
  669. });
  670. _self.unCheckNodes(true);
  671. _self.defaultChecked();
  672. _self.checkboxInit();
  673. });
  674. },
  675. updateKeySelf: function (key, data) {
  676. var options = this.config;
  677. var node = options.elem.find("[data-" + options.request.key + "='" + key + "']").children(".eleTree-node-content");
  678. var floor = Number(node.attr("eletree-floor")) + 1;
  679. data[options.request.name] && node.children(".eleTree-node-content-label").text(data[options.request.name]);
  680. data[options.request.disabled] && node.children(".eleTree-hideen").addClass("eleTree-disabled")
  681. .siblings(".eleTree-checkbox").addClass("eleTree-checkbox-disabled");
  682. // 数据更新
  683. var getData = this.keySearchToOpera(key, function (d, obj) {
  684. data[options.request.key] = d[obj.i][options.request.key];
  685. data[options.request.children] = d[obj.i][options.request.children];
  686. d[obj.i] = $.extend({}, d[obj.i], data);
  687. console.log(options.data);
  688. });
  689. },
  690. remove: function (key) {
  691. var options = this.config;
  692. var node = options.elem.find("[data-" + options.request.key + "='" + key + "']");
  693. var pElem = node.parent(".eleTree-node-group");
  694. // 数据删除
  695. this.keySearchToOpera(key, function (data, obj) {
  696. data.splice(obj.i, 1);
  697. obj.i--;
  698. obj.len--;
  699. node.length !== 0 && options.elem.find("[data-" + options.request.key + "='" + key + "']").remove();
  700. if (pElem.children(".eleTree-node").length === 0) {
  701. pElem.siblings(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon").css("color", "transparent");
  702. }
  703. });
  704. this.unCheckNodes(true);
  705. this.defaultChecked();
  706. this.checkboxInit();
  707. },
  708. append: function (key, data) {
  709. var options = this.config;
  710. var node = options.elem.find("[data-" + options.request.key + "='" + key + "']");
  711. var floor = Number(node.attr("eletree-floor")) + 1;
  712. // 数据更新
  713. this.keySearchToOpera(key, function (d, obj) {
  714. if (d[obj.i][options.request.children]) {
  715. d[obj.i][options.request.children].push(data);
  716. } else {
  717. d[obj.i][options.request.children] = [data];
  718. }
  719. var arr = d[obj.i][options.request.children];
  720. // 添加之后长度为1,则原来没有三角,添加三角
  721. if (arr.length === 1) {
  722. node.children(".eleTree-node-content").find(".eleTree-node-content-icon .layui-icon").removeAttr("style").addClass("icon-rotate");
  723. }
  724. var len = arr.length;
  725. var eletreeStatus = node.children(".eleTree-node-content").children("input.eleTree-hideen").attr("eletree-status");
  726. eletreeStatus = eletreeStatus === "2" ? "0" : eletreeStatus;
  727. node.length !== 0 && laytpl(TPL_ELEM(options, floor, eletreeStatus)).render([arr[len - 1]], function (string) {
  728. node.children(".eleTree-node-group").append(string).children().show();
  729. });
  730. });
  731. this.checkboxRender();
  732. },
  733. insertBefore: function (key, data) {
  734. var options = this.config;
  735. var node = options.elem.find("[data-" + options.request.key + "='" + key + "']");
  736. var floor = Number(node.attr("eletree-floor"));
  737. // 数据更新
  738. this.keySearchToOpera(key, function (d, obj) {
  739. d.splice(obj.i, 0, data);
  740. obj.i++;
  741. obj.len++;
  742. var eletreeStatus = node.parent(".eleTree-node-group").length === 0 ? "0" : node.parent(".eleTree-node-group").parent(".eleTree-node")
  743. .children(".eleTree-node-content").children("input.eleTree-hideen").attr("eletree-status");
  744. eletreeStatus = eletreeStatus === "2" ? "0" : eletreeStatus;
  745. node.length !== 0 && laytpl(TPL_ELEM(options, floor, eletreeStatus)).render([data], function (string) {
  746. node.before(string).prev(".eleTree-node").show();
  747. });
  748. });
  749. this.checkboxRender();
  750. },
  751. insertAfter: function (key, data) {
  752. var options = this.config;
  753. var node = options.elem.find("[data-" + options.request.key + "='" + key + "']");
  754. var floor = Number(node.attr("eletree-floor"));
  755. // 数据更新
  756. this.keySearchToOpera(key, function (d, obj) {
  757. d.splice(obj.i + 1, 0, data);
  758. obj.i++;
  759. obj.len++;
  760. var eletreeStatus = node.parent(".eleTree-node-group").length === 0 ? "0" : node.parent(".eleTree-node-group").parent(".eleTree-node")
  761. .children(".eleTree-node-content").children("input.eleTree-hideen").attr("eletree-status");
  762. eletreeStatus = eletreeStatus === "2" ? "0" : eletreeStatus;
  763. node.length !== 0 && laytpl(TPL_ELEM(options, floor, eletreeStatus)).render([data], function (string) {
  764. $(node).after(string).next(".eleTree-node").show();
  765. });
  766. });
  767. this.checkboxRender();
  768. // if(!options.lazy){
  769. // if(!options.renderAfterExpand || options.defaultExpandAll || options.defaultExpandedKeys.length>0){
  770. // this.expandAll(options.data,[],1);
  771. // }
  772. // }
  773. },
  774. getChecked: function (leafOnly, includeHalfChecked) {
  775. var options = this.config
  776. , el
  777. , arr = [];
  778. leafOnly = leafOnly || false;
  779. includeHalfChecked = includeHalfChecked || false;
  780. if (leafOnly) {
  781. el = options.elem.find(".layui-icon.leaf-icon").parent(".eleTree-node-content-icon")
  782. .siblings("input.eleTree-hideen[eletree-status='1']");
  783. } else if (includeHalfChecked) {
  784. el = options.elem.find("input.eleTree-hideen[eletree-status='1'],input.eleTree-hideen[eletree-status='2']");
  785. } else {
  786. el = options.elem.find("input.eleTree-hideen[eletree-status='1']");
  787. }
  788. el.each(function (index, item) {
  789. var obj = {};
  790. var id = $(item).parent(".eleTree-node-content").parent(".eleTree-node").attr("data-" + options.request.key);
  791. id = isNaN(id) ? id : Number(id);
  792. var label = $(item).siblings(".eleTree-node-content-label").text();
  793. obj[options.request.key] = id;
  794. obj[options.request.name] = label;
  795. obj.elem = item;
  796. obj.othis = $(item).siblings(".eleTree-checkbox").get(0)
  797. arr.push(obj);
  798. })
  799. return arr;
  800. },
  801. setChecked: function (arr, isReset) {
  802. var options = this.config;
  803. isReset = isReset || false;
  804. if (isReset) {
  805. this.unCheckNodes();
  806. options.defaultCheckedKeys = $.extend([], arr);
  807. } else {
  808. this.unCheckNodes(true);
  809. arr.forEach(function (val) {
  810. if ($.inArray(val, options.defaultCheckedKeys) === -1) {
  811. options.defaultCheckedKeys.push(val);
  812. }
  813. })
  814. }
  815. this.defaultChecked();
  816. this.checkboxInit();
  817. },
  818. unCheckNodes: function (_internal) {
  819. _internal = _internal || false; // _internal: 是否内部调用
  820. var options = this.config;
  821. options.elem.find("input.eleTree-hideen[eletree-status='1'],input.eleTree-hideen[eletree-status='2']").each(function (index, item) {
  822. $(item).attr("eletree-status", "0").prop("checked", false);
  823. // 如果外部的取消选中,则所有的记录全部取消
  824. if (!_internal) {
  825. $(item).removeAttr("data-checked");
  826. }
  827. });
  828. this.checkboxRender();
  829. },
  830. unCheckArrNodes: function (arr) {
  831. var options = this.config;
  832. arr.forEach(function (val, index) {
  833. var inp = options.elem.find(".eleTree-node[data-" + options.request.key + "='" + val + "']").children(".eleTree-node-content").children(".eleTree-hideen[eletree-status='1'],.eleTree-hideen[eletree-status='2']")
  834. if (inp.length > 0) {
  835. inp.prop("checked", true).removeAttr("data-checked").siblings(".eleTree-checkbox").trigger("click");
  836. }
  837. })
  838. },
  839. unExpandAll: function () {
  840. var options = this.config;
  841. options.elem.find(".layui-icon.icon-rotate").removeClass("icon-rotate")
  842. .parent(".eleTree-node-content-icon").parent(".eleTree-node-content")
  843. .siblings(".eleTree-node-group").children(".eleTree-node").hide();
  844. },
  845. // 节点事件
  846. nodeEvent: function () {
  847. var _self = this;
  848. var options = this.config;
  849. // 节点被点击的回调事件
  850. options.elem.on("click", ".eleTree-node-content", function (e) {
  851. var eleNode = $(this).parent(".eleTree-node");
  852. $("#tree-menu").hide().remove();
  853. layui.event.call(eleNode, MOD_NAME, 'nodeClick(' + _self.filter + ')', {
  854. node: eleNode,
  855. data: _self.reInitData(eleNode),
  856. event: e
  857. });
  858. })
  859. // 节点右键的回调事件
  860. options.elem.on("contextmenu", ".eleTree-node-content", function (e) {
  861. var eleNode = $(this).parent(".eleTree-node");
  862. layui.event.call(eleNode, MOD_NAME, 'nodeContextmenu(' + _self.filter + ')', {
  863. node: eleNode,
  864. data: _self.reInitData(eleNode),
  865. event: e
  866. });
  867. })
  868. // 节点被拖拽的回调事件
  869. options.draggable && options.elem.on("mousedown", ".eleTree-node-content", function (e) {
  870. var time = 0;
  871. var eleNode = $(this).parent(".eleTree-node");
  872. var eleFloor = Number(eleNode.attr("eletree-floor"));
  873. var groupNode = eleNode.parent(".eleTree-node-group");
  874. e.stopPropagation();
  875. options.elem.css("user-select", "none");
  876. var cloneNode = eleNode.clone(true);
  877. var temNode = eleNode.clone(true);
  878. var x = e.clientX - options.elem.offset().left;
  879. var y = e.clientY - options.elem.offset().top;
  880. options.elem.append(cloneNode);
  881. cloneNode.css({
  882. "display": "none",
  883. "opacity": 0.7,
  884. "position": "absolute",
  885. "background-color": "#f5f5f5",
  886. "width": "100%"
  887. })
  888. var currentData = _self.reInitData(eleNode);
  889. var isStop = false;
  890. $(document).on("mousemove", function (e) {
  891. // t为了区别click事件
  892. time++;
  893. if (time > 2) {
  894. var xx = e.clientX - options.elem.offset().left + 10;
  895. var yy = e.clientY - options.elem.offset().top + $(document).scrollTop() - 5; // 加上浏览器滚动高度
  896. cloneNode.css({
  897. display: "block",
  898. left: xx + "px",
  899. top: yy + "px"
  900. })
  901. }
  902. }).on("mouseup", function (e) {
  903. $(document).off("mousemove").off("mouseup");
  904. var target = $(e.target).parents(".eleTree-node").eq(0);
  905. cloneNode.remove();
  906. options.elem.css("user-select", "auto");
  907. // 当前点击的是否时最外层
  908. var isCurrentOuterMost = eleNode.parent().get(0).isEqualNode(options.elem.get(0))
  909. // 目标是否时最外层
  910. var isTargetOuterMost = $(e.target).get(0).isEqualNode(options.elem.get(0))
  911. if (isTargetOuterMost) {
  912. target = options.elem;
  913. }
  914. // 判断是否超出边界
  915. if (target.parents(options.elem).length === 0 && !isTargetOuterMost) {
  916. return;
  917. }
  918. // 判断初始与结束是否是同一个节点
  919. if (target.get(0).isEqualNode(eleNode.get(0))) {
  920. return;
  921. }
  922. // 判断是否是父节点放到子节点
  923. var tFloor = target.attr("eletree-floor");
  924. var isInChild = false;
  925. eleNode.find("[eletree-floor='" + tFloor + "']").each(function () {
  926. if (this.isEqualNode(target.get(0))) {
  927. isInChild = true;
  928. }
  929. })
  930. if (isInChild) {
  931. return;
  932. }
  933. var targetData = _self.reInitData(target);
  934. layui.event.call(target, MOD_NAME, 'nodeDrag(' + _self.filter + ')', {
  935. current: {
  936. node: eleNode,
  937. data: currentData
  938. },
  939. target: {
  940. node: target,
  941. data: targetData
  942. },
  943. stop: function () {
  944. isStop = true;
  945. }
  946. });
  947. // 拖拽是否取消
  948. if (isStop) {
  949. return false;
  950. }
  951. // 数据更改
  952. var currList = currentData.parentData.data[options.request.children]
  953. var currIndex = currentData.parentData.childIndex
  954. var currData = currentData.currentData;
  955. var tarData = targetData.currentData;
  956. // 当前是否是最外层
  957. isCurrentOuterMost ? options.data.splice(currIndex, 1) : currList.splice(currIndex, 1)
  958. // 目标是否是最外层
  959. isTargetOuterMost ? options.data.push(currData) : (function () {
  960. !tarData[options.request.children] ? tarData[options.request.children] = [] : "";
  961. tarData[options.request.children].push(currData);
  962. })()
  963. // dom互换
  964. eleNode.remove();
  965. // 最外层判断
  966. if (isTargetOuterMost) {
  967. target.append(temNode);
  968. var floor = 0;
  969. } else {
  970. target.children(".eleTree-node-group").append(temNode);
  971. var floor = Number(target.attr("eletree-floor")) + 1;
  972. }
  973. // 加floor和padding
  974. temNode.attr("eletree-floor", String(floor));
  975. temNode.children(".eleTree-node-content").css("padding-left", floor * options.indent + "px");
  976. // 通过floor差值计算子元素的floor
  977. var countFloor = eleFloor - floor;
  978. temNode.find(".eleTree-node").each(function (index, item) {
  979. var f = Number($(item).attr("eletree-floor")) - countFloor;
  980. $(item).attr("eletree-floor", String(f));
  981. $(item).children(".eleTree-node-content").css("padding-left", f * options.indent + "px");
  982. })
  983. // 原dom去三角
  984. var leaf = groupNode.children(".eleTree-node").length === 0;
  985. leaf && groupNode.siblings(".eleTree-node-content")
  986. .children(".eleTree-node-content-icon").children(".layui-icon")
  987. .removeClass("icon-rotate").css("color", "transparent");
  988. // 当前的增加三角
  989. var cLeaf = target.children(".eleTree-node-group").children(".eleTree-node").length === 0;
  990. !cLeaf && target.children(".eleTree-node-content")
  991. .children(".eleTree-node-content-icon").children(".layui-icon")
  992. .addClass("icon-rotate").removeAttr("style");
  993. _self.unCheckNodes(true);
  994. _self.defaultChecked();
  995. _self.checkboxInit();
  996. })
  997. })
  998. },
  999. rightClickMenu: function () {
  1000. var _self = this;
  1001. var options = this.config;
  1002. if (options.contextmenuList.length <= 0) {
  1003. return;
  1004. }
  1005. $(document).on("click", function () {
  1006. $("#tree-menu").hide().remove();
  1007. });
  1008. var menuStr = ['<ul id="tree-menu">'
  1009. , $.inArray("copy", options.contextmenuList) !== -1 ? '<li class="copy"><a href="javascript:;">复制</a></li>' : ''
  1010. , $.inArray("add", options.contextmenuList) !== -1 ? '<li class="add"><a href="javascript:;">新增</a></li>' +
  1011. '<li class="insertBefore"><a href="javascript:;">插入节点前</a></li>' +
  1012. '<li class="insertAfter"><a href="javascript:;">插入节点后</a></li>' +
  1013. '<li class="append"><a href="javascript:;">插入子节点</a></li>' : ""
  1014. , $.inArray("edit", options.contextmenuList) !== -1 ? '<li class="edit"><a href="javascript:;">修改</a></li>' : ''
  1015. , $.inArray("remove", options.contextmenuList) !== -1 ? '<li class="remove"><a href="javascript:;">删除</a></li>' : ''
  1016. , '</ul>'].join("");
  1017. this.treeMenu = $(menuStr);
  1018. options.elem.off("contextmenu").on("contextmenu", ".eleTree-node-content", function (e) {
  1019. var that = this;
  1020. e.stopPropagation();
  1021. e.preventDefault();
  1022. // 添加active背景
  1023. if (_self.prevClickEle) _self.prevClickEle.removeClass("eleTree-node-content-active");
  1024. $(this).addClass("eleTree-node-content-active");
  1025. var eleNode = $(this).parent(".eleTree-node");
  1026. var nodeData = _self.reInitData(eleNode);
  1027. // 菜单位置
  1028. $(document.body).after(_self.treeMenu);
  1029. $("#tree-menu li.insertBefore,#tree-menu li.insertAfter,#tree-menu li.append").hide();
  1030. $("#tree-menu li.copy,#tree-menu li.add,#tree-menu li.edit,#tree-menu li.remove").show();
  1031. $("#tree-menu").css({
  1032. left: e.pageX,
  1033. top: e.pageY
  1034. }).show();
  1035. // 复制
  1036. $("#tree-menu li.copy").off().on("click", function () {
  1037. var el = $(that).children(".eleTree-node-content-label").get(0);
  1038. var selection = window.getSelection();
  1039. var range = document.createRange();
  1040. range.selectNodeContents(el);
  1041. selection.removeAllRanges();
  1042. selection.addRange(range);
  1043. document.execCommand('Copy', 'false', null);
  1044. selection.removeAllRanges();
  1045. });
  1046. // 新增
  1047. $("#tree-menu li.add").off().on("click", function (e) {
  1048. e.stopPropagation();
  1049. $(this).hide().siblings("li.copy,li.edit,li.remove").hide();
  1050. $(this).siblings(".append,li.insertAfter,li.insertBefore").show();
  1051. })
  1052. // 添加的默认数据
  1053. var obj = {};
  1054. obj[options.request.key] = Date.now();
  1055. obj[options.request.name] = "未命名" + _self.nameIndex;
  1056. var arr = ["Append", "InsertBefore", "InsertAfter"];
  1057. arr.forEach(function (val) {
  1058. var s = val[0].toLocaleLowerCase() + val.slice(1, val.length);
  1059. $("#tree-menu li." + s).off().on("click", function (e) {
  1060. var node = $(that).parent(".eleTree-node");
  1061. var key = node.attr("data-" + options.request.key);
  1062. key = isNaN(key) ? key : Number(key);
  1063. var isStop = false;
  1064. var s = val[0].toLocaleLowerCase() + val.slice(1, val.length);
  1065. layui.event.call(node, MOD_NAME, 'node' + val + '(' + _self.filter + ')', {
  1066. node: node,
  1067. data: nodeData.currentData,
  1068. newData: obj,
  1069. // 重新设置数据
  1070. setData: function (o) {
  1071. var newObj = $.extend({}, obj, o);
  1072. this.newData = newObj
  1073. _self[s](key, newObj);
  1074. isStop = true;
  1075. },
  1076. // 停止添加
  1077. stop: function () {
  1078. isStop = true;
  1079. }
  1080. });
  1081. if (isStop) return;
  1082. _self[s](key, obj)
  1083. _self.nameIndex++;
  1084. })
  1085. })
  1086. // 编辑
  1087. $("#tree-menu li.edit").off().on("click", function (e) {
  1088. e.stopPropagation();
  1089. $("#tree-menu").hide().remove();
  1090. var node = $(that).parent(".eleTree-node");
  1091. var key = node.attr("data-" + options.request.key);
  1092. key = isNaN(key) ? key : Number(key);
  1093. var label = $(that).children(".eleTree-node-content-label").hide();
  1094. var text = label.text();
  1095. var inp = "<input type='text' value='" + text + "' class='eleTree-node-content-input' />";
  1096. label.after(inp);
  1097. label.siblings(".eleTree-node-content-input").focus().select().off().on("blur", function () {
  1098. var val = $(this).val();
  1099. var isStop = false;
  1100. var inpThis = this;
  1101. layui.event.call(node, MOD_NAME, 'nodeEdit(' + _self.filter + ')', {
  1102. node: node,
  1103. value: val,
  1104. data: nodeData.currentData,
  1105. // 停止添加
  1106. stop: function () {
  1107. isStop = true;
  1108. $(inpThis).siblings(".eleTree-node-content-label").show();
  1109. $(inpThis).remove();
  1110. }
  1111. });
  1112. if (isStop) return;
  1113. // 修改数据
  1114. _self.reInitData(eleNode).currentData[options.request.name] = val;
  1115. // 修改dom
  1116. $(this).siblings(".eleTree-node-content-label").text(val).show();
  1117. $(this).remove();
  1118. }).on("mousedown", function (e) {
  1119. // 防止input拖拽
  1120. e.stopPropagation();
  1121. })
  1122. })
  1123. // 删除
  1124. $("#tree-menu li.remove").off().on("click", function (e) {
  1125. var node = $(that).parent(".eleTree-node");
  1126. var key = node.attr("data-" + options.request.key);
  1127. key = isNaN(key) ? key : Number(key);
  1128. var isStop = false;
  1129. layui.event.call(node, MOD_NAME, 'nodeRemove(' + _self.filter + ')', {
  1130. node: node,
  1131. data: nodeData.currentData,
  1132. // 停止添加
  1133. stop: function () {
  1134. isStop = true;
  1135. }
  1136. });
  1137. if (isStop) return;
  1138. _self.remove(key);
  1139. })
  1140. _self.prevClickEle = $(this);
  1141. })
  1142. },
  1143. search: function (value) {
  1144. var options = this.config;
  1145. if (!options.searchNodeMethod || typeof options.searchNodeMethod !== "function") {
  1146. return;
  1147. }
  1148. var data = options.data;
  1149. // 数据递归
  1150. var traverse = function (data) {
  1151. data.forEach(function (val, index) {
  1152. // 所有查找到的节点增加属性
  1153. val.visible = options.searchNodeMethod(value, val);
  1154. if (val[options.request.children] && val[options.request.children].length > 0) {
  1155. traverse(val[options.request.children]);
  1156. }
  1157. //如果当前节点属性为隐藏,判断其子节点是否有显示的,如果有,则当前节点改为显示
  1158. if (!val.visible) {
  1159. var childSomeShow = false;
  1160. if (val[options.request.children] && val[options.request.children].length > 0) {
  1161. childSomeShow = val[options.request.children].some(function (v, i) {
  1162. return v.visible;
  1163. })
  1164. }
  1165. val.visible = childSomeShow;
  1166. }
  1167. // 通过节点的属性,显示隐藏各个节点,并添加删除搜索类
  1168. var el = options.elem.find("[data-" + options.request.key + "='" + val[options.request.key] + "']");
  1169. if (val.visible) {
  1170. el.removeClass("eleTree-search-hide");
  1171. // 判断父节点是否展开,如果父节点没有展开,则子节点也不要显示
  1172. var parentEl = el.parent(".eleTree-node-group").parent(".eleTree-node");
  1173. var isParentOpen = parentEl.children(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon.layui-icon-triangle-r").hasClass("icon-rotate")
  1174. if ((parentEl.length > 0 && isParentOpen) || parentEl.length === 0) {
  1175. el.show();
  1176. }
  1177. } else {
  1178. el.hide().addClass("eleTree-search-hide");
  1179. }
  1180. // 删除子层属性
  1181. if (val[options.request.children] && val[options.request.children].length > 0) {
  1182. val[options.request.children].forEach(function (v, i) {
  1183. delete v.visible;
  1184. })
  1185. }
  1186. })
  1187. }
  1188. traverse(data);
  1189. // 删除最外层属性
  1190. var arr = [];
  1191. data.forEach(function (val) {
  1192. arr.push(val.visible);
  1193. delete val.visible;
  1194. })
  1195. // 如果第一层的所有的都隐藏,则显示文本
  1196. if (arr.every(function (v) {
  1197. return v === false;
  1198. })) {
  1199. laytpl(TPL_NoText()).render(options, function (string) {
  1200. options.elem.append(string);
  1201. });
  1202. } else {
  1203. options.elem.children(".eleTree-noText").remove();
  1204. }
  1205. }
  1206. }
  1207. exports(MOD_NAME, eleTree);
  1208. })