eleTree.js 70 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417
  1. /**
  2. * @Name: 基于layui的tree重写
  3. * @Author: 李祥
  4. * @License:MIT
  5. * 最近修改时间: 2019/05/20
  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 {{# if(d[i].visible===false){ }}eleTree-search-hide{{# } }}" 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" lay-ignore eleTree-status="1" checked data-checked class="layui-hide eleTree-hideen ',
  129. '{{# }else{ }}',
  130. '<input type="checkbox" name="eleTree-node" lay-ignore eleTree-status='+status+' class="layui-hide 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() {}, // 加载子树数据的方法,仅当 lazy 属性为true 时生效
  179. draggable: false, // 是否开启拖拽节点功能
  180. contextmenuList: [], // 启用右键菜单,支持的操作有:"copy","add","edit","remove"
  181. searchNodeMethod: null, // 对树节点进行筛选时执行的方法,返回 true 表示这个节点可以显示,返回 false 则表示这个节点会被隐藏
  182. method: "get",
  183. url: "",
  184. contentType: "",
  185. headers: {},
  186. done: null,
  187. response: {
  188. statusName: "code",
  189. statusCode: 0,
  190. dataName: "data"
  191. },
  192. request: {
  193. name: "label",
  194. key: "id",
  195. children: "children",
  196. disabled: "disabled",
  197. checked: "checked",
  198. isLeaf: "isLeaf"
  199. }
  200. },
  201. render: function() {
  202. if(this.config.indent>30){
  203. this.config.indent=30;
  204. }else if(this.config.indent<10){
  205. this.config.indent=10;
  206. }
  207. var options=this.config;
  208. options.where=options.where || {};
  209. if(!options.elem) return hint.error("缺少elem参数");
  210. options.elem=typeof options.elem === "string" ? $(options.elem) : options.elem;
  211. this.filter=options.elem.attr("lay-filter");
  212. // load加载框
  213. 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>')
  214. // 判断加载方式
  215. if(options.data.length===0){
  216. this.ajaxGetData();
  217. }else{
  218. this.renderData();
  219. }
  220. },
  221. renderData: function() {
  222. var options=this.config;
  223. $(this.config.elem).off(); // 取消事件绑定,防止多次绑定事件
  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. // 选择祖父
  315. var selectParentsFn=function() {
  316. if(!options.checkStrictly){
  317. var eleNode1=sibNode.children(".eleTree-node").eq(0);
  318. if(eleNode1.length!==0){
  319. var siblingNode1=eleNode1.siblings(".eleTree-node");
  320. var item1=eleNode1.children(".eleTree-node-content").children(".eleTree-hideen").get(0);
  321. _self.selectParents(item1,eleNode1,siblingNode1);
  322. }
  323. }
  324. }
  325. var data=_self.reInitData(eleNode);
  326. var d=data.currentData;
  327. // 是否懒加载
  328. if(options.lazy && el.hasClass("lazy-icon")){
  329. el.removeClass("layui-icon-triangle-r").addClass("layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop");
  330. options.load(d,function(getData) {
  331. // 如果原来有数据则合并,没有则赋值
  332. if(d[options.request.children]){
  333. d[options.request.children]=d[options.request.children].concat(getData);
  334. }else{
  335. d[options.request.children]=getData;
  336. }
  337. var eletreeStatus=eleTreeNodeContent.children("input.eleTree-hideen").attr("eletree-status");
  338. if(d[options.request.children] && d[options.request.children].length>0){
  339. // 只渲染获取到的数据
  340. laytpl(TPL_ELEM(options,floor,eletreeStatus)).render(getData, function(string){
  341. sibNode.append(string).children().show("fast");
  342. });
  343. }else{
  344. el.css("color","transparent").addClass("leaf-icon");
  345. }
  346. el.removeClass("lazy-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop").addClass("layui-icon-triangle-r icon-rotate");
  347. // 懒加载子元素选择祖父(待写)
  348. selectParentsFn();
  349. _self.checkboxRender();
  350. })
  351. }else{
  352. var eletreeStatus=eleTreeNodeContent.children("input.eleTree-hideen").attr("eletree-status");
  353. d[options.request.children] && d[options.request.children].length>0 && laytpl(TPL_ELEM(options,floor,eletreeStatus)).render(d[options.request.children], function(string){
  354. sibNode.append(string);
  355. });
  356. // 选择祖父
  357. selectParentsFn();
  358. _self.checkboxRender();
  359. }
  360. }
  361. // 显示隐藏没有搜索类的
  362. sibNode.children(".eleTree-node:not(.eleTree-search-hide)").show("fast");
  363. el.addClass("icon-rotate");
  364. // 手风琴效果
  365. if(options.accordion){
  366. var node=eleTreeNodeContent.parent(".eleTree-node").siblings(".eleTree-node");
  367. node.children(".eleTree-node-group").children(".eleTree-node:not(.eleTree-search-hide)").hide("fast");
  368. node.children(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon").removeClass("icon-rotate");
  369. }
  370. })
  371. },
  372. // checkbox选中
  373. checkboxEvent: function() {
  374. var options=this.config;
  375. var _self=this;
  376. var checkOnClickNode=options.checkOnClickNode?".eleTree-node-content":".eleTree-checkbox";
  377. // input添加属性eleTree-status:即input的三种状态,"0":未选中,"1":选中,"2":子孙部分选中
  378. options.elem.on("click",checkOnClickNode,function(e) {
  379. e.stopPropagation();
  380. var eleTreeNodeContent=$(this).parent(".eleTree-node").length===0?$(this).parent(".eleTree-node-content"):$(this);
  381. var checkbox=eleTreeNodeContent.children(".eleTree-checkbox");
  382. if(checkbox.hasClass("eleTree-checkbox-disabled")) return;
  383. // 获取点击所在数据
  384. var node=eleTreeNodeContent.parent(".eleTree-node");
  385. // var d=_self.reInitData(node).currentData;
  386. // 实际的input
  387. var inp=checkbox.siblings(".eleTree-hideen").get(0);
  388. var childNode=eleTreeNodeContent.siblings(".eleTree-node-group").find("input[name='eleTree-node']");
  389. // 添加active背景
  390. if(_self.prevClickEle) _self.prevClickEle.removeClass("eleTree-node-content-active");
  391. if(options.highlightCurrent) eleTreeNodeContent.addClass("eleTree-node-content-active");
  392. _self.prevClickEle=eleTreeNodeContent;
  393. if(!inp) return;
  394. if(inp.checked){
  395. // 反选自身
  396. $(inp).prop("checked",false).attr("eleTree-status","0");
  397. // 点击祖父层选中子孙层
  398. if(!options.checkStrictly){
  399. childNode.prop("checked",false);
  400. childNode.attr("eleTree-status","0");
  401. }
  402. }else{
  403. // 反选自身
  404. $(inp).prop("checked",true).attr("eleTree-status","1");
  405. // 点击祖父层选中子孙层
  406. if(!options.checkStrictly){
  407. childNode.prop("checked",true).attr("eleTree-status","1");
  408. }
  409. }
  410. var eleNode=eleTreeNodeContent.parent(".eleTree-node");
  411. // 点击子孙层选中祖父层(递归)
  412. if(!options.checkStrictly){
  413. var siblingNode=eleNode.siblings(".eleTree-node");
  414. // 点击子孙层选中祖父层(递归)
  415. _self.selectParents(inp,eleNode,siblingNode);
  416. }
  417. _self.checkboxRender();
  418. layui.event.call(inp, MOD_NAME, 'nodeChecked('+ _self.filter +')', {
  419. node: eleNode,
  420. data: _self.reInitData(eleNode),
  421. isChecked: inp.checked
  422. });
  423. })
  424. },
  425. // 对后台数据有 checked:true 的默认选中项渲染父子层
  426. checkboxInit: function() {
  427. var options=this.config;
  428. var _self=this;
  429. options.elem.find("input[data-checked]").each(function(index,item) {
  430. var checkboxEl=$(item).siblings(".eleTree-checkbox");
  431. var childNode=checkboxEl.parent(".eleTree-node-content").siblings(".eleTree-node-group").find("input[name='eleTree-node']");
  432. // 选择当前
  433. $(item).prop("checked","checked").attr("eleTree-status","1");
  434. checkboxEl.addClass("eleTree-checkbox-checked");
  435. checkboxEl.children("i").addClass("layui-icon-ok").removeClass("eleTree-checkbox-line");
  436. if(options.checkStrictly) return;
  437. // 选择子孙
  438. childNode.prop("checked","checked").attr("eleTree-status","1");
  439. childNode.siblings(".eleTree-checkbox").addClass("eleTree-checkbox-checked");
  440. childNode.siblings(".eleTree-checkbox").children("i").addClass("layui-icon-ok").removeClass("eleTree-checkbox-line");
  441. // 选择祖父
  442. var eleNode=checkboxEl.parent(".eleTree-node-content").parent(".eleTree-node");
  443. var siblingNode=eleNode.siblings(".eleTree-node");
  444. _self.selectParents(item,eleNode,siblingNode);
  445. })
  446. _self.checkboxRender();
  447. },
  448. // 通过子元素选中祖父元素
  449. selectParents: function(inp,eleNode,siblingNode) {
  450. // inp: 实际input(dom元素)
  451. // eleNode: input父层类(.eleTree-node)
  452. // siblingNode: 父层同级兄弟
  453. while (Number(eleNode.attr("eletree-floor"))!==0) {
  454. // 同级input状态存入数组
  455. var arr=[];
  456. arr.push($(inp).attr("eleTree-status"));
  457. siblingNode.each(function(index,item) {
  458. var siblingIsChecked=$(item).children(".eleTree-node-content").children("input[name='eleTree-node']").attr("eleTree-status");
  459. arr.push(siblingIsChecked);
  460. })
  461. // 父元素的实际input
  462. var parentInput=eleNode.parent(".eleTree-node-group").siblings(".eleTree-node-content").children("input[name='eleTree-node']");
  463. // 父元素的checkbox替代
  464. var parentCheckbox=parentInput.siblings(".eleTree-checkbox");
  465. // 子都选中则选中父
  466. if(arr.every(function(val) {
  467. return val==="1";
  468. })){
  469. parentInput.prop("checked",true).attr("eleTree-status","1");
  470. }
  471. // 子有一个未选中则checkbox第三种状态
  472. if(arr.some(function(val) {
  473. return val==="0" || val==="2";
  474. })){
  475. parentInput.attr("eleTree-status","2");
  476. }
  477. // 子全部未选中则取消父选中(并且取消第三种状态)
  478. if(arr.every(function(val) {
  479. return val==="0";
  480. })){
  481. parentInput.prop("checked",false);
  482. parentInput.attr("eleTree-status","0");
  483. }
  484. var parentNode=eleNode.parents("[eletree-floor='"+(Number(eleNode.attr("eletree-floor"))-1)+"']");
  485. var parentCheckbox=parentNode.children(".eleTree-node-content").children("input[name='eleTree-node']").get(0);
  486. var parentSiblingNode=parentNode.siblings(".eleTree-node");
  487. eleNode=parentNode;
  488. inp=parentCheckbox;
  489. siblingNode=parentSiblingNode;
  490. }
  491. },
  492. // 初始展开所有
  493. expandAll: function(data,arr,floor,isMethodsExpandAll) {
  494. var options=this.config;
  495. var _self=this;
  496. data.forEach(function(val,index) {
  497. arr.push(index);
  498. if(val[options.request.children] && val[options.request.children].length>0){
  499. var el=options.elem.children(".eleTree-node").eq(arr[0]).children(".eleTree-node-group");
  500. for(var i=1;i<arr.length;i++){
  501. el=el.children(".eleTree-node").eq(arr[i]).children(".eleTree-node-group");
  502. }
  503. laytpl(TPL_ELEM(options,floor)).render(val[options.request.children], function(string){
  504. el.append(string);
  505. // 判断是否展开所有
  506. if(options.defaultExpandAll || isMethodsExpandAll){
  507. el.siblings(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon").addClass("icon-rotate");
  508. el.children().show();
  509. }else if(options.defaultExpandedKeys.length>0) {
  510. // 继续展开祖父层
  511. var f=function(eleP) {
  512. if(options.autoExpandParent){
  513. eleP.parents(".eleTree-node").each(function(i,item) {
  514. if($(item).data(options.request.key)){
  515. $(item).children(".eleTree-node-group").siblings(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon").addClass("icon-rotate");
  516. $(item).children(".eleTree-node-group").children().show();
  517. }
  518. })
  519. }
  520. }
  521. // 展开指定id项
  522. var id=el.parent(".eleTree-node").data(options.request.key);
  523. if($.inArray(id,options.defaultExpandedKeys)!==-1){
  524. // 直接展开子节点
  525. el.siblings(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon").addClass("icon-rotate");
  526. el.children().show();
  527. // 展开子项是否继续展开祖父项
  528. f(el.parent(".eleTree-node[data-"+options.request.key+"]"));
  529. }else{
  530. // 如当前节点的子节点有展开项,则展开当前子节点的祖父层
  531. el.children(".eleTree-node").each(function(index, item) {
  532. var id=$(item).data(options.request.key);
  533. if($.inArray(id,options.defaultExpandedKeys)!==-1){
  534. f($(item));
  535. return false;
  536. }
  537. })
  538. }
  539. }
  540. });
  541. floor++;
  542. _self.expandAll(val[options.request.children],arr,floor,isMethodsExpandAll);
  543. floor--;
  544. }
  545. // 重置数组索引
  546. arr.pop();
  547. })
  548. },
  549. // 选中单个节点
  550. checkedOneNode: function(nodeContent){
  551. var options=this.config;
  552. var inp=nodeContent.children("input.eleTree-hideen").get(0);
  553. $(inp).prop("checked",true).attr("eleTree-status","1");
  554. if(options.checkStrictly) return;
  555. // 点击祖父层选中子孙层
  556. var childNode=nodeContent.siblings(".eleTree-node-group").find("input[name='eleTree-node']");
  557. childNode.prop("checked",true).attr("eleTree-status","1");
  558. var eleNode=nodeContent.parent(".eleTree-node");
  559. var siblingNode=eleNode.siblings(".eleTree-node");
  560. // 点击子孙层选中祖父层(递归)
  561. this.selectParents(inp,eleNode,siblingNode);
  562. },
  563. // 初始默认选中
  564. defaultChecked: function(dataChecked) {
  565. var options=this.config;
  566. var _self=this;
  567. var arr=dataChecked || options.defaultCheckedKeys;
  568. if(arr.length===0){
  569. return false;
  570. }
  571. arr.forEach(function(val,index) {
  572. var nodeContent=options.elem.find("[data-"+options.request.key+"='"+val+"']").children(".eleTree-node-content");
  573. nodeContent.length>0 && _self.checkedOneNode(nodeContent);
  574. })
  575. this.checkboxInit();
  576. },
  577. // 自定义checkbox解析
  578. checkboxRender: function() {
  579. var options=this.config;
  580. options.elem.find(".eleTree-checkbox").remove();
  581. options.elem.find("input.eleTree-hideen[type=checkbox]").each(function(index,item){
  582. if($(item).hasClass("eleTree-disabled")){
  583. $(item).after('<div class="eleTree-checkbox eleTree-checkbox-disabled"><i class="layui-icon"></i></div>');
  584. }else{
  585. $(item).after('<div class="eleTree-checkbox"><i class="layui-icon"></i></div>');
  586. }
  587. var checkbox=$(item).siblings(".eleTree-checkbox");
  588. if($(item).attr("eletree-status")==="1"){
  589. checkbox.addClass("eleTree-checkbox-checked");
  590. checkbox.children("i").addClass("layui-icon-ok").removeClass("eleTree-checkbox-line");
  591. }else if($(item).attr("eletree-status")==="0"){
  592. checkbox.removeClass("eleTree-checkbox-checked");
  593. checkbox.children("i").removeClass("layui-icon-ok eleTree-checkbox-line");
  594. }else if($(item).attr("eletree-status")==="2"){
  595. checkbox.addClass("eleTree-checkbox-checked");
  596. checkbox.children("i").removeClass("layui-icon-ok").addClass("eleTree-checkbox-line");
  597. }
  598. })
  599. },
  600. // 通过dom节点找对应数据
  601. reInitData: function(node) {
  602. var options=this.config;
  603. var i=node.index();
  604. var floor=Number(node.attr("eletree-floor"));
  605. var arr=[]; // 节点对应的index
  606. while (floor>=0) {
  607. arr.push(i);
  608. floor=floor-1;
  609. node=node.parents("[eletree-floor='"+floor+"']");
  610. i=node.index();
  611. }
  612. arr=arr.reverse();
  613. var oData=this.config.data;
  614. // 当前节点的父节点数据
  615. var parentData=oData[arr[0]];
  616. // 当前节点的data数据
  617. var d = oData[arr[0]];
  618. for(var j = 1; j<arr.length; j++){
  619. d = d[options.request.children]?d[options.request.children][arr[j]]:d;
  620. }
  621. for(var k = 1; k<arr.length-1; k++){
  622. parentData = parentData[options.request.children]?parentData[options.request.children][arr[k]]:parentData;
  623. }
  624. return {
  625. currentData: d,
  626. parentData: {
  627. data: parentData,
  628. childIndex: arr[arr.length-1]
  629. },
  630. index: arr
  631. }
  632. },
  633. // 通过key查找数据
  634. keySearchToOpera: function(key,callback) {
  635. var options=this.config;
  636. var _self=this;
  637. // 查找数据
  638. var fn=function(data) {
  639. var obj={
  640. i: 0,
  641. len: data.length
  642. }
  643. for(;obj.i<obj.len;obj.i++){
  644. if(data[obj.i][options.request.key]!=key){
  645. if(data[obj.i][options.request.children] && data[obj.i][options.request.children].length>0){
  646. fn(data[obj.i][options.request.children]);
  647. }
  648. }else{
  649. callback(data,obj);
  650. }
  651. }
  652. }
  653. fn(options.data);
  654. },
  655. updateKeyChildren: function(key,data) {
  656. var options=this.config;
  657. var node=options.elem.find("[data-"+options.request.key+"='"+key+"']");
  658. var floor=Number(node.attr("eletree-floor"))+1;
  659. var _self=this;
  660. this.keySearchToOpera(key,function(d,obj) {
  661. // 数据更新
  662. d[obj.i][options.request.children]=data;
  663. // dom更新
  664. node.length!==0 && laytpl(TPL_ELEM(options,floor)).render(data, function(string){
  665. $(node).children(".eleTree-node-group").empty().append(string);
  666. options.defaultExpandAll && $(node).children(".eleTree-node-group").children().show();
  667. });
  668. _self.unCheckNodes(true);
  669. _self.defaultChecked();
  670. });
  671. },
  672. updateKeySelf: function(key,data) {
  673. var options=this.config;
  674. var node=options.elem.find("[data-"+options.request.key+"='"+key+"']").children(".eleTree-node-content");
  675. var floor=Number(node.attr("eletree-floor"))+1;
  676. data[options.request.name] && node.children(".eleTree-node-content-label").text(data[options.request.name]);
  677. data[options.request.disabled] && node.children(".eleTree-hideen").addClass("eleTree-disabled")
  678. .siblings(".eleTree-checkbox").addClass("eleTree-checkbox-disabled");
  679. // 数据更新
  680. var getData=this.keySearchToOpera(key,function(d,obj) {
  681. data[options.request.key]=d[obj.i][options.request.key];
  682. data[options.request.children]=d[obj.i][options.request.children];
  683. d[obj.i]=$.extend({},d[obj.i],data);
  684. console.log(options.data);
  685. });
  686. },
  687. remove: function(key) {
  688. var options=this.config;
  689. var node=options.elem.find("[data-"+options.request.key+"='"+key+"']");
  690. var pElem=node.parent(".eleTree-node-group");
  691. // 数据删除
  692. this.keySearchToOpera(key,function(data,obj) {
  693. data.splice(obj.i,1);
  694. obj.i--;
  695. obj.len--;
  696. node.length!==0 && options.elem.find("[data-"+options.request.key+"='"+key+"']").remove();
  697. if(pElem.children(".eleTree-node").length===0){
  698. pElem.siblings(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon").css("color", "transparent");
  699. }
  700. });
  701. this.unCheckNodes(true);
  702. this.defaultChecked();
  703. this.checkboxInit();
  704. },
  705. append: function(key,data) {
  706. var options=this.config;
  707. // 如果不传key,则直接添加到根节点
  708. if(typeof key==="object" && key!==null){
  709. data=key;
  710. key=null;
  711. }
  712. if(key===null || key===""){
  713. options.data.push(data);
  714. laytpl(TPL_ELEM(options,0,"0")).render([data], function(string){
  715. $(options.elem).append(string);
  716. $(options.elem).children(".eleTree-node:last").show();
  717. });
  718. this.checkboxRender();
  719. return;
  720. }
  721. // 传key则添加到子节点
  722. var node=options.elem.find("[data-"+options.request.key+"='"+key+"']");
  723. var floor=Number(node.attr("eletree-floor"))+1;
  724. // 数据更新
  725. this.keySearchToOpera(key,function(d,obj) {
  726. if(d[obj.i][options.request.children]){
  727. d[obj.i][options.request.children].push(data);
  728. }else{
  729. d[obj.i][options.request.children]=[data];
  730. }
  731. var arr=d[obj.i][options.request.children];
  732. var icon=node.children(".eleTree-node-content").find(".eleTree-node-content-icon .layui-icon");
  733. // 添加之后长度为1,则原来没有三角,添加三角
  734. if(arr.length===1){
  735. icon.removeAttr("style");
  736. }
  737. // 判断原来是否没有展开
  738. if(!icon.hasClass("icon-rotate")){
  739. var expandOnClickNode=options.expandOnClickNode?node.children(".eleTree-node-content"):node.children(".eleTree-node-content").children(".eleTree-node-content-icon");
  740. expandOnClickNode.trigger("click");
  741. }
  742. // 判断节点是否已存在
  743. var isExist=false;
  744. node.children(".eleTree-node-group").children(".eleTree-node").each(function(index,item){
  745. if(data[options.request.key]==$(item).data(options.request.key)){
  746. isExist=true;
  747. }
  748. })
  749. if(!isExist){
  750. var len=arr.length;
  751. var eletreeStatus=node.children(".eleTree-node-content").children("input.eleTree-hideen").attr("eletree-status");
  752. eletreeStatus=eletreeStatus==="2" ? "0" : eletreeStatus;
  753. node.length!==0 && laytpl(TPL_ELEM(options,floor,eletreeStatus)).render([arr[len-1]], function(string){
  754. node.children(".eleTree-node-group").append(string).children().show();
  755. });
  756. }
  757. });
  758. this.checkboxRender();
  759. },
  760. insertBefore: function(key,data) {
  761. var options=this.config;
  762. var node=options.elem.find("[data-"+options.request.key+"='"+key+"']");
  763. var floor=Number(node.attr("eletree-floor"));
  764. // 数据更新
  765. this.keySearchToOpera(key,function(d,obj) {
  766. d.splice(obj.i,0,data);
  767. obj.i++;
  768. obj.len++;
  769. var eletreeStatus=node.parent(".eleTree-node-group").length===0 ? "0" : node.parent(".eleTree-node-group").parent(".eleTree-node")
  770. .children(".eleTree-node-content").children("input.eleTree-hideen").attr("eletree-status");
  771. eletreeStatus=eletreeStatus==="2" ? "0" : eletreeStatus;
  772. node.length!==0 && laytpl(TPL_ELEM(options,floor,eletreeStatus)).render([data], function(string){
  773. node.before(string).prev(".eleTree-node").show();
  774. });
  775. });
  776. this.checkboxRender();
  777. },
  778. insertAfter: function(key,data) {
  779. var options=this.config;
  780. var node=options.elem.find("[data-"+options.request.key+"='"+key+"']");
  781. var floor=Number(node.attr("eletree-floor"));
  782. // 数据更新
  783. this.keySearchToOpera(key,function(d,obj) {
  784. d.splice(obj.i+1,0,data);
  785. obj.i++;
  786. obj.len++;
  787. var eletreeStatus=node.parent(".eleTree-node-group").length===0 ? "0" : node.parent(".eleTree-node-group").parent(".eleTree-node")
  788. .children(".eleTree-node-content").children("input.eleTree-hideen").attr("eletree-status");
  789. eletreeStatus=eletreeStatus==="2" ? "0" : eletreeStatus;
  790. node.length!==0 && laytpl(TPL_ELEM(options,floor,eletreeStatus)).render([data], function(string){
  791. $(node).after(string).next(".eleTree-node").show();
  792. });
  793. });
  794. this.checkboxRender();
  795. // if(!options.lazy){
  796. // if(!options.renderAfterExpand || options.defaultExpandAll || options.defaultExpandedKeys.length>0){
  797. // this.expandAll(options.data,[],1);
  798. // }
  799. // }
  800. },
  801. getChecked: function(leafOnly, includeHalfChecked) {
  802. var options=this.config
  803. ,el
  804. ,arr=[];
  805. leafOnly=leafOnly || false;
  806. includeHalfChecked=includeHalfChecked || false;
  807. if(leafOnly){
  808. el=options.elem.find(".layui-icon.leaf-icon").parent(".eleTree-node-content-icon")
  809. .siblings("input.eleTree-hideen[eletree-status='1']");
  810. }else if(includeHalfChecked){
  811. el=options.elem.find("input.eleTree-hideen[eletree-status='1'],input.eleTree-hideen[eletree-status='2']");
  812. }else{
  813. el=options.elem.find("input.eleTree-hideen[eletree-status='1']");
  814. }
  815. el.each(function(index,item) {
  816. var obj={};
  817. var id=$(item).parent(".eleTree-node-content").parent(".eleTree-node").data(options.request.key);
  818. var label=$(item).siblings(".eleTree-node-content-label").text();
  819. obj[options.request.key]=id;
  820. obj[options.request.name]=label;
  821. obj.elem=item;
  822. obj.othis=$(item).siblings(".eleTree-checkbox").get(0)
  823. arr.push(obj);
  824. })
  825. return arr;
  826. },
  827. setChecked: function(arr,isReset) {
  828. var options=this.config;
  829. isReset=isReset || false;
  830. if(isReset){
  831. this.unCheckNodes();
  832. options.defaultCheckedKeys=$.extend([],arr);
  833. }else{
  834. this.unCheckNodes(true);
  835. arr.forEach(function(val) {
  836. if($.inArray(val,options.defaultCheckedKeys)===-1){
  837. options.defaultCheckedKeys.push(val);
  838. }
  839. })
  840. }
  841. this.defaultChecked();
  842. },
  843. unCheckNodes: function(_internal) {
  844. _internal=_internal || false; // _internal: 是否内部调用
  845. var options=this.config;
  846. options.elem.find("input.eleTree-hideen[eletree-status='1'],input.eleTree-hideen[eletree-status='2']").each(function(index,item) {
  847. $(item).attr("eletree-status","0").prop("checked",false);
  848. // 如果外部的取消选中,则所有的记录全部取消
  849. if(!_internal){
  850. $(item).removeAttr("data-checked");
  851. }
  852. });
  853. this.checkboxRender();
  854. },
  855. unCheckArrNodes: function(arr) {
  856. var options=this.config;
  857. var dataChecked=[];
  858. options.elem.find(".eleTree-hideen[eletree-status='1']").each(function(index,item) {
  859. var id=$(item).parent(".eleTree-node-content").parent(".eleTree-node").data(options.request.key);
  860. // 获取所有被选中项,并去除arr中包含的数据
  861. if(arr.some(function(val) {
  862. return val==id;
  863. })){
  864. // 如果id在arr数组中,则清除dom上面的checked数据
  865. $(item).removeAttr("data-checked");
  866. return;
  867. }
  868. dataChecked.push(id);
  869. })
  870. // 更新defaultCheckedKeys数据
  871. for(var j=0;j<options.defaultCheckedKeys.length;j++){
  872. if(!dataChecked.some(function(val) {
  873. return val==options.defaultCheckedKeys[j];
  874. })){
  875. options.defaultCheckedKeys.splice(j,1);
  876. j--;
  877. }
  878. }
  879. this.unCheckNodes(true);
  880. this.defaultChecked(dataChecked);
  881. },
  882. unExpandAll: function() {
  883. var options=this.config;
  884. options.elem.find(".layui-icon.icon-rotate").removeClass("icon-rotate")
  885. .parent(".eleTree-node-content-icon").parent(".eleTree-node-content")
  886. .siblings(".eleTree-node-group").children(".eleTree-node").hide();
  887. },
  888. // 节点事件
  889. nodeEvent: function() {
  890. var _self=this;
  891. var options=this.config;
  892. // 节点被点击的回调事件
  893. options.elem.on("click",".eleTree-node-content",function(e) {
  894. var eleNode=$(this).parent(".eleTree-node");
  895. $("#tree-menu").hide().remove();
  896. layui.event.call(eleNode, MOD_NAME, 'nodeClick('+ _self.filter +')', {
  897. node: eleNode,
  898. data: _self.reInitData(eleNode),
  899. event: e
  900. });
  901. })
  902. // 节点右键的回调事件
  903. options.elem.on("contextmenu",".eleTree-node-content",function(e) {
  904. var eleNode=$(this).parent(".eleTree-node");
  905. layui.event.call(eleNode, MOD_NAME, 'nodeContextmenu('+ _self.filter +')', {
  906. node: eleNode,
  907. data: _self.reInitData(eleNode),
  908. event: e
  909. });
  910. })
  911. // 节点被拖拽的回调事件
  912. options.draggable && options.elem.on("mousedown",".eleTree-node-content",function(e) {
  913. var time=0;
  914. var eleNode=$(this).parent(".eleTree-node");
  915. var eleFloor=Number(eleNode.attr("eletree-floor"));
  916. var groupNode=eleNode.parent(".eleTree-node-group");
  917. e.stopPropagation();
  918. options.elem.css("user-select","none");
  919. var cloneNode=eleNode.clone(true);
  920. var temNode=eleNode.clone(true);
  921. var x=e.clientX-options.elem.offset().left;
  922. var y=e.clientY-options.elem.offset().top;
  923. options.elem.append(cloneNode);
  924. cloneNode.css({
  925. "display": "none",
  926. "opacity": 0.7,
  927. "position": "absolute",
  928. "background-color": "#f5f5f5",
  929. "width": "100%"
  930. })
  931. var currentData=_self.reInitData(eleNode);
  932. var isStop=false;
  933. $(document).on("mousemove",function(e) {
  934. // t为了区别click事件
  935. time++;
  936. if(time>2){
  937. var xx=e.clientX-options.elem.offset().left+10;
  938. var yy=e.clientY-options.elem.offset().top+$(document).scrollTop()-5; // 加上浏览器滚动高度
  939. cloneNode.css({
  940. display: "block",
  941. left: xx+"px",
  942. top: yy+"px"
  943. })
  944. }
  945. }).on("mouseup",function(e) {
  946. $(document).off("mousemove").off("mouseup");
  947. var target=$(e.target).parents(".eleTree-node").eq(0);
  948. cloneNode.remove();
  949. options.elem.css("user-select","auto");
  950. // 当前点击的是否时最外层
  951. var isCurrentOuterMost=eleNode.parent().get(0).isEqualNode(options.elem.get(0))
  952. // 目标是否时最外层
  953. var isTargetOuterMost=$(e.target).get(0).isEqualNode(options.elem.get(0))
  954. if(isTargetOuterMost){
  955. target=options.elem;
  956. }
  957. // 判断是否超出边界
  958. if(target.parents(options.elem).length===0 && !isTargetOuterMost){
  959. return;
  960. }
  961. // 判断初始与结束是否是同一个节点
  962. if(target.get(0).isEqualNode(eleNode.get(0))){
  963. return;
  964. }
  965. // 判断是否是父节点放到子节点
  966. var tFloor=target.attr("eletree-floor");
  967. var isInChild=false;
  968. eleNode.find("[eletree-floor='"+tFloor+"']").each(function() {
  969. if(this.isEqualNode(target.get(0))){
  970. isInChild=true;
  971. }
  972. })
  973. if(isInChild){
  974. return;
  975. }
  976. var targetData=_self.reInitData(target);
  977. layui.event.call(target, MOD_NAME, 'nodeDrag('+ _self.filter +')', {
  978. current: {
  979. node: eleNode,
  980. data: currentData
  981. },
  982. target: {
  983. node: target,
  984. data: targetData
  985. },
  986. stop: function() {
  987. isStop=true;
  988. }
  989. });
  990. // 拖拽是否取消
  991. if(isStop){
  992. return false;
  993. }
  994. // 数据更改
  995. var currList=currentData.parentData.data[options.request.children]
  996. var currIndex=currentData.parentData.childIndex
  997. var currData=currentData.currentData;
  998. var tarData=targetData.currentData;
  999. // 当前是否是最外层
  1000. isCurrentOuterMost ? options.data.splice(currIndex,1) : currList.splice(currIndex,1)
  1001. // 目标是否是最外层
  1002. isTargetOuterMost ? options.data.push(currData) : (function() {
  1003. !tarData[options.request.children] ? tarData[options.request.children]=[] : "";
  1004. tarData[options.request.children].push(currData);
  1005. })()
  1006. // dom互换
  1007. eleNode.remove();
  1008. var floor=null;
  1009. // 最外层判断
  1010. if(isTargetOuterMost){
  1011. target.append(temNode);
  1012. floor=0;
  1013. }else{
  1014. target.children(".eleTree-node-group").append(temNode);
  1015. floor=Number(target.attr("eletree-floor"))+1;
  1016. }
  1017. // 加floor和padding
  1018. temNode.attr("eletree-floor",String(floor));
  1019. temNode.children(".eleTree-node-content").css("padding-left",floor*options.indent+"px");
  1020. // 通过floor差值计算子元素的floor
  1021. var countFloor=eleFloor-floor;
  1022. temNode.find(".eleTree-node").each(function(index,item) {
  1023. var f=Number($(item).attr("eletree-floor"))-countFloor;
  1024. $(item).attr("eletree-floor",String(f));
  1025. $(item).children(".eleTree-node-content").css("padding-left",f*options.indent+"px");
  1026. })
  1027. // 原dom去三角
  1028. var leaf=groupNode.children(".eleTree-node").length===0;
  1029. leaf && groupNode.siblings(".eleTree-node-content")
  1030. .children(".eleTree-node-content-icon").children(".layui-icon")
  1031. .removeClass("icon-rotate").css("color","transparent");
  1032. // 当前的增加三角
  1033. var cLeaf=target.children(".eleTree-node-group").children(".eleTree-node").length===0;
  1034. !cLeaf && target.children(".eleTree-node-content")
  1035. .children(".eleTree-node-content-icon").children(".layui-icon")
  1036. .addClass("icon-rotate").removeAttr("style");
  1037. _self.unCheckNodes(true);
  1038. _self.defaultChecked();
  1039. _self.checkboxInit();
  1040. })
  1041. })
  1042. },
  1043. rightClickMenu: function() {
  1044. var _self=this;
  1045. var options=this.config;
  1046. if(options.contextmenuList.length<=0){
  1047. return;
  1048. }
  1049. $(document).on("click",function() {
  1050. $("#tree-menu").hide().remove();
  1051. });
  1052. var customizeMenu=[]; // 用户自定义的
  1053. var internalMenu=["copy","add","add.async","insertBefore","insertAfter","append","edit","edit.async","remove","remove.async"]; // 系统自带的
  1054. var customizeStr='';
  1055. options.contextmenuList.forEach(function(val) {
  1056. if($.inArray(val,internalMenu)===-1){
  1057. customizeMenu.push(val);
  1058. customizeStr+='<li class="'+(val.eventName || val)+'"><a href="javascript:;">'+(val.text || val)+'</a></li>';
  1059. }
  1060. })
  1061. var menuStr=['<ul id="tree-menu">'
  1062. ,$.inArray("copy",options.contextmenuList)!==-1?'<li class="copy"><a href="javascript:;">复制</a></li>':''
  1063. ,($.inArray("add",options.contextmenuList)!==-1 || $.inArray("add.async",options.contextmenuList)!==-1)?'<li class="add"><a href="javascript:;">新增</a></li>'+
  1064. '<li class="insertBefore"><a href="javascript:;">插入节点前</a></li>'+
  1065. '<li class="insertAfter"><a href="javascript:;">插入节点后</a></li>'+
  1066. '<li class="append"><a href="javascript:;">插入子节点</a></li>' : ""
  1067. ,($.inArray("edit",options.contextmenuList)!==-1 || $.inArray("edit.async",options.contextmenuList)!==-1)?'<li class="edit"><a href="javascript:;">修改</a></li>':''
  1068. ,($.inArray("remove",options.contextmenuList)!==-1 || $.inArray("remove.async",options.contextmenuList)!==-1)?'<li class="remove"><a href="javascript:;">删除</a></li>':''
  1069. ,customizeStr
  1070. ,'</ul>'].join("");
  1071. this.treeMenu=$(menuStr);
  1072. options.elem.off("contextmenu").on("contextmenu",".eleTree-node-content",function(e) {
  1073. var that=this;
  1074. e.stopPropagation();
  1075. e.preventDefault();
  1076. // 添加active背景
  1077. if(_self.prevClickEle) _self.prevClickEle.removeClass("eleTree-node-content-active");
  1078. $(this).addClass("eleTree-node-content-active");
  1079. var eleNode=$(this).parent(".eleTree-node");
  1080. var nodeData=_self.reInitData(eleNode);
  1081. // 菜单位置
  1082. $(document.body).after(_self.treeMenu);
  1083. $("#tree-menu").find("li.append,li.insertAfter,li.insertBefore").hide();
  1084. $("#tree-menu").find(":not(li.append,li.insertAfter,li.insertBefore)").show();
  1085. $("#tree-menu").css({
  1086. left: e.clientX+$(document).scrollLeft(),
  1087. top: e.clientY+$(document).scrollTop()
  1088. }).show();
  1089. // 复制
  1090. $("#tree-menu li.copy").off().on("click",function() {
  1091. var el = $(that).children(".eleTree-node-content-label").get(0);
  1092. var selection = window.getSelection();
  1093. var range = document.createRange();
  1094. range.selectNodeContents(el);
  1095. selection.removeAllRanges();
  1096. selection.addRange(range);
  1097. document.execCommand('Copy', 'false', null);
  1098. selection.removeAllRanges();
  1099. });
  1100. // 新增
  1101. $("#tree-menu li.add").off().on("click",function(e) {
  1102. e.stopPropagation();
  1103. $(this).hide().siblings("li:not(.append,.insertAfter,.insertBefore)").hide();
  1104. $(this).siblings(".append,li.insertAfter,li.insertBefore").show();
  1105. })
  1106. // 添加的默认数据
  1107. var obj={};
  1108. obj[options.request.key]=Date.now();
  1109. obj[options.request.name]="未命名"+_self.nameIndex;
  1110. if(options.lazy){
  1111. obj[options.request.isLeaf]=true;
  1112. }
  1113. var arr=["Append","InsertBefore","InsertAfter"];
  1114. arr.forEach(function(val) {
  1115. var s=val[0].toLocaleLowerCase()+val.slice(1,val.length);
  1116. $("#tree-menu li."+s).off().on("click",function(e) {
  1117. var node=$(that).parent(".eleTree-node");
  1118. var key=node.data(options.request.key);
  1119. var isStop=false;
  1120. var s=val[0].toLocaleLowerCase()+val.slice(1,val.length);
  1121. // 每次只能添加一条数据,不可以批量添加
  1122. _self[s](key,obj);
  1123. var nodeArr=[];
  1124. node.children(".eleTree-node-group").children(".eleTree-node").each(function(i,itemNode) {
  1125. nodeArr.push(itemNode);
  1126. })
  1127. node.siblings(".eleTree-node").each(function(i,itemNode) {
  1128. nodeArr.push(itemNode);
  1129. })
  1130. $.each(nodeArr, function(i,itemNode) {
  1131. if(obj[options.request.key]===$(itemNode).data(options.request.key)){
  1132. var label=$(itemNode).children(".eleTree-node-content").children(".eleTree-node-content-label").hide();
  1133. var text=label.text();
  1134. var inp="<input type='text' value='"+obj[options.request.name]+"' class='eleTree-node-content-input' />";
  1135. label.after(inp);
  1136. label.siblings(".eleTree-node-content-input").focus().off().on("blur",function() {
  1137. var v=$(this).val();
  1138. obj[options.request.name]=v;
  1139. var inpThis=this;
  1140. layui.event.call(node, MOD_NAME, 'node'+val+'('+ _self.filter +')', {
  1141. node: node,
  1142. data: nodeData.currentData,
  1143. newData: obj,
  1144. // 重新设置数据
  1145. setData: function(o) {
  1146. // obj[options.request.key]=Date.now();
  1147. obj[options.request.name]=v;
  1148. if(options.lazy){
  1149. obj[options.request.isLeaf]=true;
  1150. }
  1151. var newObj=$.extend({},obj,o);
  1152. this.newData=newObj;
  1153. // 修改数据
  1154. var d=_self.reInitData($(itemNode)).currentData;
  1155. d[options.request.name]=newObj[options.request.name];
  1156. d[options.request.key]=newObj[options.request.key];
  1157. // 修改dom
  1158. $(inpThis).siblings(".eleTree-node-content-label").text(newObj[options.request.name]).show();
  1159. $(itemNode).attr("data-"+options.request.key,newObj[options.request.key]); // 改变页面上面的显示的key,之后可以获取dom
  1160. $(itemNode).data(options.request.key,newObj[options.request.key]); // 改变data数据,之后可以通过data获取key
  1161. $(inpThis).remove();
  1162. _self.nameIndex++;
  1163. isStop=true;
  1164. },
  1165. // 停止添加
  1166. stop: function() {
  1167. isStop=true;
  1168. this.newData={};
  1169. _self.remove(obj[options.request.key]);
  1170. }
  1171. });
  1172. // 不是异步添加
  1173. if($.inArray("add.async",options.contextmenuList)===-1){
  1174. if(isStop) return;
  1175. // 修改数据
  1176. _self.reInitData($(itemNode)).currentData[options.request.name]=v;
  1177. // 修改dom
  1178. $(this).siblings(".eleTree-node-content-label").text(v).show();
  1179. $(this).remove();
  1180. _self.nameIndex++;
  1181. }
  1182. }).on("mousedown",function(e) {
  1183. // 防止input拖拽
  1184. e.stopPropagation();
  1185. }).on("click",function(e) {
  1186. e.stopPropagation();
  1187. })
  1188. }
  1189. })
  1190. })
  1191. })
  1192. // 编辑
  1193. $("#tree-menu li.edit").off().on("click",function(e) {
  1194. e.stopPropagation();
  1195. $("#tree-menu").hide().remove();
  1196. var node=$(that).parent(".eleTree-node");
  1197. var key=node.data(options.request.key);
  1198. var label=$(that).children(".eleTree-node-content-label").hide();
  1199. var text=label.text();
  1200. var inp="<input type='text' value='"+text+"' class='eleTree-node-content-input' />";
  1201. label.after(inp);
  1202. label.siblings(".eleTree-node-content-input").focus().select().off().on("blur",function() {
  1203. var val=$(this).val();
  1204. var isStop=false;
  1205. var inpThis=this;
  1206. layui.event.call(node, MOD_NAME, 'nodeEdit('+ _self.filter +')', {
  1207. node: node,
  1208. value: val,
  1209. data: nodeData.currentData,
  1210. // 停止添加
  1211. stop: function() {
  1212. isStop=true;
  1213. $(inpThis).siblings(".eleTree-node-content-label").show();
  1214. $(inpThis).remove();
  1215. },
  1216. async: function() {
  1217. if(isStop) return;
  1218. // 修改数据
  1219. _self.reInitData(eleNode).currentData[options.request.name]=val;
  1220. // 修改dom
  1221. $(inpThis).siblings(".eleTree-node-content-label").text(val).show();
  1222. $(inpThis).remove();
  1223. }
  1224. });
  1225. // 不是异步
  1226. if($.inArray("edit.async",options.contextmenuList)===-1){
  1227. if(isStop) return;
  1228. // 修改数据
  1229. _self.reInitData(eleNode).currentData[options.request.name]=val;
  1230. // 修改dom
  1231. $(this).siblings(".eleTree-node-content-label").text(val).show();
  1232. $(this).remove();
  1233. }
  1234. }).on("mousedown",function(e) {
  1235. // 防止input拖拽
  1236. e.stopPropagation();
  1237. })
  1238. })
  1239. // 删除
  1240. $("#tree-menu li.remove").off().on("click",function(e) {
  1241. var node=$(that).parent(".eleTree-node");
  1242. var key=node.data(options.request.key);
  1243. var isStop=false;
  1244. layui.event.call(node, MOD_NAME, 'nodeRemove('+ _self.filter +')', {
  1245. node: node,
  1246. data: nodeData.currentData,
  1247. // 停止添加
  1248. stop: function() {
  1249. isStop=true;
  1250. return this;
  1251. },
  1252. async: function() {
  1253. if(isStop) return;
  1254. _self.remove(key);
  1255. return this;
  1256. }
  1257. });
  1258. // 不是异步
  1259. if($.inArray("remove.async",options.contextmenuList)===-1){
  1260. if(isStop) return;
  1261. _self.remove(key);
  1262. }
  1263. })
  1264. // 自定义菜单回调
  1265. customizeMenu.forEach(function(val) {
  1266. var text=val.eventName || val;
  1267. $("#tree-menu li."+text).off().on("click",function() {
  1268. var node=$(that).parent(".eleTree-node");
  1269. var isStop=false;
  1270. layui.event.call(node, MOD_NAME, 'node'+text.replace(text.charAt(0),text.charAt(0).toUpperCase())+'('+ _self.filter +')', {
  1271. node: node,
  1272. data: nodeData.currentData,
  1273. });
  1274. });
  1275. })
  1276. _self.prevClickEle=$(this);
  1277. })
  1278. },
  1279. search: function(value) {
  1280. var options=this.config;
  1281. if(!options.searchNodeMethod || typeof options.searchNodeMethod !== "function"){
  1282. return;
  1283. }
  1284. var data=options.data;
  1285. // 数据递归
  1286. var traverse=function(data) {
  1287. data.forEach(function(val,index) {
  1288. // 所有查找到的节点增加属性
  1289. val.visible=options.searchNodeMethod(value,val);
  1290. if(val[options.request.children] && val[options.request.children].length>0){
  1291. traverse(val[options.request.children]);
  1292. }
  1293. //如果当前节点属性为隐藏,判断其子节点是否有显示的,如果有,则当前节点改为显示
  1294. if(!val.visible){
  1295. var childSomeShow = false;
  1296. if(val[options.request.children] && val[options.request.children].length>0){
  1297. childSomeShow=val[options.request.children].some(function(v,i) {
  1298. return v.visible;
  1299. })
  1300. }
  1301. val.visible = childSomeShow;
  1302. }
  1303. // 通过节点的属性,显示隐藏各个节点,并添加删除搜索类
  1304. var el=options.elem.find("[data-"+options.request.key+"='"+val[options.request.key]+"']");
  1305. if(val.visible){
  1306. el.removeClass("eleTree-search-hide");
  1307. // 判断父节点是否展开,如果父节点没有展开,则子节点也不要显示
  1308. var parentEl=el.parent(".eleTree-node-group").parent(".eleTree-node");
  1309. var isParentOpen=parentEl.children(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon.layui-icon-triangle-r").hasClass("icon-rotate")
  1310. if((parentEl.length>0 && isParentOpen) || parentEl.length===0){
  1311. el.show();
  1312. }
  1313. }else{
  1314. el.hide().addClass("eleTree-search-hide");
  1315. }
  1316. // 删除子层属性
  1317. // if(val[options.request.children] && val[options.request.children].length>0){
  1318. // val[options.request.children].forEach(function(v,i) {
  1319. // delete v.visible;
  1320. // })
  1321. // }
  1322. })
  1323. }
  1324. traverse(data);
  1325. // 删除最外层属性
  1326. var arr=[];
  1327. data.forEach(function(val) {
  1328. arr.push(val.visible);
  1329. // delete val.visible;
  1330. })
  1331. var isNotext=options.elem.children(".eleTree-noText");
  1332. // 如果第一层的所有的都隐藏,则显示文本
  1333. if(arr.every(function(v) {
  1334. return v===false;
  1335. })){
  1336. if(isNotext.length===0){
  1337. laytpl(TPL_NoText()).render(options, function(string){
  1338. options.elem.append(string);
  1339. });
  1340. }
  1341. }else{
  1342. isNotext.remove();
  1343. }
  1344. }
  1345. }
  1346. exports(MOD_NAME,eleTree);
  1347. })