eleTree.js 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890
  1. /**
  2. * 基于layui的tree重写
  3. * author: hsianglee
  4. * 最近修改时间: 2018/10/27
  5. * 说明:因isEqualNode,ie8不支持拖拽功能
  6. */
  7. layui.define(["jquery","laytpl","layer","form"], function (exports) {
  8. var $ = layui.jquery;
  9. var laytpl = layui.laytpl;
  10. var layer = layui.layer;
  11. var form = layui.form;
  12. function Class(option) {
  13. this.option=option; // 获取传入的数据
  14. this.elem="";
  15. this.data=[];
  16. this.showCheckbox=this.option.showCheckbox;
  17. this.drag=this.option.drag;
  18. this.accordion=this.option.accordion;
  19. this.lazy=this.option.lazy;
  20. this.loadData=this.option.loadData;
  21. this.contextmenuList=[];
  22. this.node=""; // 生成树的dom字符串
  23. this.checkedData=[]; // 被选中的数据
  24. this.prevClickEle; // 记录上次点击的dom
  25. this.treeMenu=""; // 右键菜单字符串
  26. this.filter="";
  27. this.isIE8=navigator.appName=="Microsoft Internet Explorer" && navigator.appVersion.split(";")[1].replace(/[ ]/g,"")=="MSIE8.0";
  28. this.render();
  29. }
  30. Class.prototype={
  31. constructor: Class,
  32. // 初始化参数数据
  33. render: function () {
  34. var self=this;
  35. self.option.elem?(function(){
  36. self.elem=self.option.elem;
  37. })():(function() {
  38. throw "缺少elem节点选择器";
  39. })();
  40. self.contextmenuList=self.option.contextmenuList?self.option.contextmenuList:[];
  41. self.lazy && !self.loadData && (function() {
  42. throw "缺少懒加载回调函数";
  43. })()
  44. self.filter=$(self.elem).attr("lay-filter");
  45. // 判断data参数
  46. if(self.option.data){
  47. self.data=self.option.data;
  48. self.init();
  49. return;
  50. }
  51. // 判断url参数
  52. if(self.option.url){
  53. $.ajax({
  54. url: self.option.url,
  55. type: self.option.type?self.option.type:"get",
  56. data: self.option.where?self.option.where:{},
  57. success: function(data){
  58. if(data.Code===0){
  59. self.data=data.Data;
  60. self.init();
  61. return;
  62. }
  63. layer.alert(data.Msg, { title: "选择器"+self.elem+"获取数据失败", icon: 2 });
  64. }
  65. });
  66. return;
  67. }
  68. throw "选择器"+self.elem+"缺少data或url参数";
  69. },
  70. // 初始化容器和标签
  71. init: function () {
  72. var self=this;
  73. this.node="";
  74. this.es5ArrMethods();
  75. $(this.elem).empty();
  76. $(this.elem).off();
  77. this.nodeInit(this.data,0,false);
  78. $(this.elem).html(this.node);
  79. this.checkboxEvent();
  80. // 更新选中的数据
  81. this.getCheckedData();
  82. this.drag && this.nodeDrag();
  83. this.eleTreeEvent();
  84. this.contextmenuList.length && this.contextmenuList.length>0 && this.rightClickMenu();
  85. this.checkInit();
  86. },
  87. // 增加foreach,some,every方法支持ie8
  88. es5ArrMethods: function() {
  89. if (!Array.prototype.every) {
  90. Array.prototype.every = function (every_fun, thisArg) {
  91. var _this = null,
  92. iKey = 0,
  93. len = this.length; //无符号右移
  94. if (typeof every_fun !== "function") {
  95. throw new TypeError("every_fun is not a function");
  96. }
  97. if (thisArg) {
  98. _this = thisArg;
  99. }//绑定执行环境
  100. for (; iKey < len; iKey++) {
  101. var key_Value = this[iKey];
  102. if(!every_fun.call(_this, key_Value, iKey, this)){
  103. return false;
  104. };
  105. }
  106. return true;
  107. }
  108. }
  109. if (!Array.prototype.some) {
  110. Array.prototype.some = function (some_fun, thisArg) {
  111. var _this = null,
  112. iKey = 0,
  113. arr_len = this.length;
  114. if (typeof some_fun != 'function') {
  115. throw new typeError('some_fun is not a function')
  116. }
  117. if (thisArg) {
  118. _this = thisArg;
  119. }
  120. for (; iKey < arr_len; iKey++) {
  121. var key_value = this[iKey];
  122. if (some_fun.call(_this, key_value, iKey, this)) {
  123. return true;
  124. }
  125. }
  126. return false;
  127. }
  128. }
  129. if (!Array.prototype.forEach) {
  130. Array.prototype.forEach = function(callback/*, thisArg*/) {
  131. var T, k;
  132. if (this == null) {
  133. throw new TypeError('this is null or not defined');
  134. }
  135. var O = Object(this);
  136. var len = O.length >>> 0; // 所有非数值转换成0,所有大于等于 0 等数取整数部分
  137. if (typeof callback !== 'function') {
  138. throw new TypeError(callback + ' is not a function');
  139. }
  140. if (arguments.length > 1) {
  141. T = arguments[1];
  142. }
  143. k = 0;
  144. while (k < len) {
  145. var kValue;
  146. if (k in O) {
  147. kValue = O[k];
  148. callback.call(T, kValue, k, O);
  149. }
  150. k++;
  151. }
  152. };
  153. }
  154. },
  155. // dom生成
  156. nodeInit: function(arr,count,spread) {
  157. // count: 第几层
  158. // spread: 是否不展开
  159. var self=this;
  160. var a=[];
  161. arr.forEach(function(val,index) {
  162. var b=['<div class="eleTree-node ',spread?'eleTree-hide':"",'" eleTree-floor="'+count+'">'
  163. ,'<div class="eleTree-node-content" style="padding-left: '+18*count+'px;">'
  164. ,'<span class="eleTree-node-content-icon">'
  165. // 判断叶子节点
  166. ,(function() {
  167. var fn=function(lazyClassStr) {
  168. if(self.isIE8){
  169. var s='<i class="layui-icon '+lazyClassStr;
  170. if(val.spread){
  171. s+='layui-icon-triangle-d ';
  172. }else{
  173. s+='layui-icon-triangle-r ';
  174. }
  175. s+=' "></i>'
  176. }else{
  177. var s='<i class="layui-icon layui-icon-triangle-r '+lazyClassStr;
  178. if(val.spread){
  179. s+='icon-rotate';
  180. }
  181. s+=' "></i>'
  182. }
  183. return s;
  184. }
  185. if(val.children && val.children.length>0){
  186. return fn("");
  187. }else if(self.lazy && !val.children && !val.isLeaf){
  188. // 懒加载
  189. return fn("lazy-icon ")
  190. }else{
  191. return '<i class="layui-icon layui-icon-triangle-r" style="color: transparent;"></i>'
  192. }
  193. })()
  194. ,'</span>'
  195. // 判断是否启用checkbox
  196. ,(function() {
  197. var s='';
  198. if(self.showCheckbox){
  199. s+='<input type="checkbox" name="eleTree-node"';
  200. if(val.checked){
  201. s+=' eleTree-status="1" checked '
  202. }else{
  203. s+=' eleTree-status="0"'
  204. }
  205. s+='class="eleTree-hideen '
  206. if(val.disabled){
  207. s+='eleTree-disabled'
  208. }
  209. s+='" >';
  210. }
  211. return s;
  212. })()
  213. ,'<span class="eleTree-node-content-label">'+val.label+'</span>'
  214. ,'</div>'
  215. ,'<div class="eleTree-node-group">'
  216. ,(function() {
  217. if(val.children && val.children.length>0){
  218. return self.nodeInit(val.children,count+1,!val.spread); // 获取已经遍历完的子节点
  219. }
  220. })()
  221. ,'</div>'
  222. ,'</div>'];
  223. a=a.concat(b);
  224. },this);
  225. this.node=a.join("");
  226. return this.node; // 返回已经遍历完的子节点
  227. },
  228. // 手风琴效果
  229. accordionFn: function(ele,d) {
  230. if(!this.accordion) return;
  231. // 手风琴
  232. var parentSibling=ele.parent(".eleTree-node").siblings(".eleTree-node");
  233. parentSibling.children(".eleTree-node-group").children().hide("fast");
  234. if(this.isIE8){
  235. parentSibling.children(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon").removeClass("layui-icon-triangle-d").addClass("layui-icon-triangle-r");
  236. }else{
  237. parentSibling.children(".eleTree-node-content").find(".layui-icon-triangle-r").removeClass("icon-rotate");
  238. }
  239. var parentData=d.parentData;
  240. // 最外层判断
  241. if(d.index.length===1){
  242. this.data.forEach(function(val,index) {
  243. if(index!==parentData.childIndex){
  244. delete val.spread;
  245. }
  246. })
  247. }else{
  248. parentData.data.children.forEach(function(val,index) {
  249. if(index!==parentData.childIndex){
  250. delete val.spread;
  251. }
  252. })
  253. }
  254. },
  255. // 展开合并动画
  256. eleTreeEvent: function() {
  257. var self=this;
  258. $(this.elem).on("click",".eleTree-node-content",function(e) {
  259. e.stopPropagation();
  260. // 添加active背景
  261. if(self.prevClickEle) self.prevClickEle.removeClass("eleTree-node-content-active");
  262. $(this).addClass("eleTree-node-content-active");
  263. // 获取点击所在数据
  264. var node=$(this).parent(".eleTree-node ");
  265. var data=self.reInitData(node);
  266. var d=data.currentData;
  267. // 切换下拉
  268. var el=$(this).children(".eleTree-node-content-icon").children(".layui-icon");
  269. if(self.isIE8) {
  270. // ie8
  271. if(el.hasClass("layui-icon-triangle-d")){
  272. // 合并
  273. $(this).siblings(".eleTree-node-group").children().hide("fast");
  274. el.removeClass("layui-icon-triangle-d").addClass("layui-icon-triangle-r");
  275. // 数据修改
  276. delete d.spread;
  277. }else{
  278. // 展开
  279. // 懒加载数据
  280. if(self.lazy && el.hasClass("lazy-icon")){
  281. el.removeClass("layui-icon-triangle-r").addClass("layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop");
  282. self.loadData(d,function(childrenData) {
  283. d.children=childrenData;
  284. self.render();
  285. })
  286. }
  287. $(this).siblings(".eleTree-node-group").children().show("fast");
  288. el.addClass("layui-icon-triangle-d").removeClass("layui-icon-triangle-r");
  289. // 数据修改
  290. d.spread=true;
  291. self.accordionFn($(this),data);
  292. }
  293. }else{
  294. if(el.hasClass("icon-rotate")){
  295. // 合并
  296. $(this).siblings(".eleTree-node-group").children().hide("fast");
  297. el.removeClass("icon-rotate");
  298. // 数据修改
  299. delete d.spread;
  300. }else{
  301. // 展开
  302. // 懒加载数据
  303. if(self.lazy && el.hasClass("lazy-icon")){
  304. el.removeClass("layui-icon-triangle-r icon-rotate").addClass("layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop");
  305. self.loadData(d,function(childrenData) {
  306. d.children=childrenData;
  307. self.render();
  308. })
  309. }
  310. $(this).siblings(".eleTree-node-group").children().show("fast");
  311. el.addClass("icon-rotate");
  312. // 数据修改
  313. d.spread=true;
  314. self.accordionFn($(this),data);
  315. }
  316. }
  317. self.prevClickEle=$(this);
  318. // 数据返回
  319. layui.event.call(this, "eleTree", 'toggleSlide('+ self.filter +')', {
  320. data: self.data
  321. ,currentData: d
  322. });
  323. $("#tree-menu").hide().remove();
  324. })
  325. $(document).on("click",function() {
  326. $("#tree-menu").hide().remove();
  327. });
  328. },
  329. // 右键菜单
  330. rightClickMenu: function() {
  331. var self=this;
  332. var menuStr=['<ul id="tree-menu" lay-filter="treeMenu">'
  333. ,$.inArray("copy",this.contextmenuList)!==-1?'<li class="copy"><a href="javascript:;">复制</a></li>':''
  334. ,$.inArray("add",this.contextmenuList)!==-1?'<li class="add"><a href="javascript:;">新增</a></li>':''
  335. ,$.inArray("edit",this.contextmenuList)!==-1?'<li class="edit"><a href="javascript:;">修改</a></li>':''
  336. ,$.inArray("remove",this.contextmenuList)!==-1?'<li class="remove"><a href="javascript:;">删除</a></li>':''
  337. ,'</ul>'].join("");
  338. this.treeMenu=$(menuStr);
  339. $(this.elem).on("contextmenu",".eleTree-node-content",function(e) {
  340. var _self=this;
  341. e.stopPropagation();
  342. e.preventDefault();
  343. // 添加active背景
  344. if(self.prevClickEle) self.prevClickEle.removeClass("eleTree-node-content-active");
  345. $(this).addClass("eleTree-node-content-active");
  346. // 菜单位置
  347. $(document.body).after(self.treeMenu);
  348. $("#tree-menu").css({
  349. left: e.pageX,
  350. top: e.pageY
  351. }).show();
  352. // 复制
  353. $("#tree-menu li.copy").off().on("click",function() {
  354. var el = $(_self).children(".eleTree-node-content-label").get(0);
  355. var selection = window.getSelection();
  356. var range = document.createRange();
  357. range.selectNodeContents(el);
  358. selection.removeAllRanges();
  359. selection.addRange(range);
  360. document.execCommand('Copy', 'false', null);
  361. selection.removeAllRanges();
  362. });
  363. // 新增
  364. $("#tree-menu li.add").off().on("click",function() {
  365. layer.prompt({title: "请输入label值"},function(value, index, elem){
  366. // 判断当前是否选中,若选中,则新增的子元素也应该选中
  367. var isChecked=$(_self).children(".eleTree-hideen").attr("eletree-status")==="1";
  368. // 数据修改
  369. var node=$(_self).parent(".eleTree-node ");
  370. var data=self.reInitData(node);
  371. var d=data.currentData;
  372. d.children?"":d.children=[];
  373. var obj={
  374. label: value
  375. }
  376. isChecked?obj.checked=true:"";
  377. d.children.push(obj);
  378. d.spread=true;
  379. self.accordionFn($(_self),data);
  380. // 数据返回
  381. layui.event.call(_self, "eleTree", 'add('+ self.filter +')', {
  382. value: value
  383. ,data: self.data
  384. ,currentData: d
  385. });
  386. // dom修改
  387. var floor=Number($(_self).parent(".eleTree-node").attr("eletree-floor"))+1;
  388. var isLeaf=$(_self).siblings(".eleTree-node-group").children(".eleTree-node").length===0;
  389. isLeaf && $(_self).children(".eleTree-node-content-icon").children("i").css("color","#c0c4cc").addClass("icon-rotate");
  390. var s=['<div class="eleTree-node" eleTree-floor="'+floor+'">'
  391. ,'<div class="eleTree-node-content" style="padding-left: '+18*floor+'px;">'
  392. ,'<span class="eleTree-node-content-icon">'
  393. ,'<i class="layui-icon layui-icon-triangle-r" style="color: transparent;"></i>'
  394. ,'</span>'
  395. // 判断是否启用checkbox
  396. ,(function() {
  397. var s="";
  398. if(self.showCheckbox){
  399. s+='<input type="checkbox" name="eleTree-node" class="eleTree-hideen"';
  400. s+=isChecked?' eleTree-status="1"':' eleTree-status="0"'
  401. s+='>'
  402. }
  403. return s;
  404. })()
  405. ,'<span class="eleTree-node-content-label">'+value+'</span>'
  406. ,'</div>'
  407. ,'<div class="eleTree-node-group">'
  408. ,'</div>'
  409. ,'</div>'].join("");
  410. $(_self).siblings(".eleTree-node-group").append(s);
  411. // checkbox解析
  412. var inp=$(_self).siblings(".eleTree-node-group").children(".eleTree-node:last").children(".eleTree-node-content").children("input.eleTree-hideen[type=checkbox]");
  413. var checkStr=['<div class="eleTree-checkbox '
  414. ,isChecked?'eleTree-checkbox-checked':''
  415. ,'"><i class="layui-icon '
  416. ,isChecked?'layui-icon-ok':''
  417. ,'"></i></div>'].join("");
  418. inp.after(checkStr);
  419. layer.close(index);
  420. });
  421. });
  422. // 编辑
  423. $("#tree-menu li.edit").off().on("click",function() {
  424. layer.prompt({
  425. value: $(_self).children(".eleTree-node-content-label").text(),
  426. title: '请输入修改的label值'
  427. },function(value, index, elem){
  428. // 数据修改
  429. var node=$(_self).parent(".eleTree-node ");
  430. var d=self.reInitData(node).currentData;
  431. d.label=value;
  432. // 数据返回
  433. layui.event.call(_self, "eleTree", 'edit('+ self.filter +')', {
  434. value: value
  435. ,data: self.data
  436. ,currentData: d
  437. });
  438. // dom修改
  439. $(_self).children(".eleTree-node-content-label").text(value);
  440. layer.close(index);
  441. });
  442. });
  443. // 删除
  444. $("#tree-menu li.remove").off().on("click",function() {
  445. // 数据删除
  446. var node=$(_self).parent(".eleTree-node ");
  447. var data=self.reInitData(node);
  448. var d=data.parentData.data;
  449. var arr=data.index;
  450. // 最外层判断
  451. if(arr.length===1){
  452. self.data.splice(arr[arr.length-1],1);
  453. }else{
  454. if(d["children"]){
  455. d["children"].splice(arr[arr.length-1],1);
  456. d["children"].length===0 && delete d["children"];
  457. }
  458. }
  459. // 数据返回
  460. layui.event.call(_self, "eleTree", 'remove('+ self.filter +')', {
  461. data: self.data
  462. ,parentData: d
  463. });
  464. // dom删除
  465. var tem=$(_self).parent(".eleTree-node").parent(".eleTree-node-group");
  466. $(_self).parent(".eleTree-node").remove();
  467. var isLeaf=tem.children(".eleTree-node").length===0;
  468. isLeaf && tem.siblings(".eleTree-node-content").children(".eleTree-node-content-icon").children("i").css("color","transparent").removeClass("icon-rotate");
  469. });
  470. self.prevClickEle=$(this);
  471. })
  472. },
  473. // 自定义checkbox解析
  474. checkboxRender: function() {
  475. $(this.elem).find(this.elem+" .eleTree-checkbox").remove();
  476. $(this.elem+" input.eleTree-hideen[type=checkbox]").each(function(index,item){
  477. if($(item).hasClass("eleTree-disabled")){
  478. $(item).after('<div class="eleTree-checkbox eleTree-checkbox-disabled"><i class="layui-icon"></i></div>');
  479. }else{
  480. $(item).after('<div class="eleTree-checkbox"><i class="layui-icon"></i></div>');
  481. }
  482. })
  483. },
  484. // 通过子孙选中祖父(递归)
  485. selectParents: function(inp,eleNode,siblingNode) {
  486. // inp: 实际input(dom元素)
  487. // eleNode: input父层类(.eleTree-node)
  488. // siblingNode: 父层同级兄弟
  489. while (Number(eleNode.attr("eletree-floor"))!==0) {
  490. // 同级input状态存入数组
  491. var arr=[];
  492. arr.push($(inp).attr("eleTree-status"));
  493. siblingNode.each(function(index,item) {
  494. var siblingIsChecked=$(item).children(".eleTree-node-content").children("input[name='eleTree-node']").attr("eleTree-status");
  495. arr.push(siblingIsChecked);
  496. })
  497. // 父元素的实际input
  498. var parentInput=eleNode.parent(".eleTree-node-group").siblings(".eleTree-node-content").children("input[name='eleTree-node']");
  499. // 父元素的checkbox替代
  500. var parentCheckbox=parentInput.siblings(".eleTree-checkbox");
  501. // 父元素的icon
  502. var parentIcon=parentCheckbox.children("i");
  503. if(arr.every(function(val) {
  504. return val==="1";
  505. })){
  506. // 子都选中则选中父
  507. parentInput.prop("checked","checked").attr("eleTree-status","1");
  508. parentCheckbox.addClass("eleTree-checkbox-checked");
  509. parentIcon.addClass("layui-icon-ok").removeClass("eleTree-checkbox-line");
  510. }
  511. if(arr.some(function(val) {
  512. return val==="0" || val==="2";
  513. })){
  514. // 子有一个未选中则checkbox第三种状态
  515. // parentInput.prop("checked","checked");
  516. parentInput.attr("eleTree-status","2");
  517. parentCheckbox.addClass("eleTree-checkbox-checked");
  518. parentIcon.removeClass("layui-icon-ok").addClass("eleTree-checkbox-line");
  519. }
  520. if(arr.every(function(val) {
  521. return val==="0";
  522. })){
  523. // 子全部未选中则取消父选中(并且取消第三种状态)
  524. parentInput.removeAttr("checked");
  525. parentInput.attr("eleTree-status","0");
  526. parentCheckbox.removeClass("eleTree-checkbox-checked");
  527. parentIcon.removeClass("layui-icon-ok eleTree-checkbox-line");
  528. }
  529. var parentNode=eleNode.parents("[eletree-floor='"+(Number(eleNode.attr("eletree-floor"))-1)+"']");
  530. var parentCheckbox=parentNode.children(".eleTree-node-content").children("input[name='eleTree-node']").get(0);
  531. var parentSiblingNode=parentNode.siblings(".eleTree-node");
  532. eleNode=parentNode;
  533. inp=parentCheckbox;
  534. siblingNode=parentSiblingNode;
  535. }
  536. },
  537. // checkbox添加选中事件
  538. checkboxEvent: function() {
  539. var self=this;
  540. this.checkboxRender();
  541. // input添加属性eleTree-status:即input的三种状态,"0":未选中,"1":选中,"2":子孙部分选中
  542. $(this.elem).on("click",".eleTree-checkbox",function(e) {
  543. e.stopPropagation();
  544. if($(this).hasClass("eleTree-checkbox-disabled")) return;
  545. // 获取点击所在数据
  546. var node=$(this).parent(".eleTree-node-content").parent(".eleTree-node ");
  547. var d=self.reInitData(node).currentData;
  548. // 实际的input
  549. var inp=$(this).siblings(".eleTree-hideen").get(0);
  550. if(inp.checked){
  551. $(inp).removeAttr("checked").attr("eleTree-status","0");
  552. $(this).removeClass("eleTree-checkbox-checked");
  553. $(this).children("i").removeClass("layui-icon-ok eleTree-checkbox-line");
  554. // 数据更新
  555. delete d.checked;
  556. }else{
  557. $(inp).prop("checked","checked").attr("eleTree-status","1");
  558. $(this).addClass("eleTree-checkbox-checked");
  559. $(this).children("i").addClass("layui-icon-ok").removeClass("eleTree-checkbox-line");
  560. d.checked=true;
  561. }
  562. var childNode=$(inp).parent(".eleTree-node-content").siblings(".eleTree-node-group").find("input[name='eleTree-node']");
  563. // 点击祖父层选中子孙层
  564. inp.checked?(function() {
  565. childNode.prop("checked","checked").attr("eleTree-status","1");
  566. childNode.siblings(".eleTree-checkbox").addClass("eleTree-checkbox-checked");
  567. childNode.siblings(".eleTree-checkbox").children("i").addClass("layui-icon-ok").removeClass("eleTree-checkbox-line");
  568. })():(function() {
  569. childNode.removeAttr("checked");
  570. childNode.attr("eleTree-status","0");
  571. childNode.siblings(".eleTree-checkbox").removeClass("eleTree-checkbox-checked");
  572. childNode.siblings(".eleTree-checkbox").children("i").removeClass("layui-icon-ok eleTree-checkbox-line");
  573. })();
  574. var eleNode=$(inp).parent(".eleTree-node-content").parent(".eleTree-node");
  575. var siblingNode=eleNode.siblings(".eleTree-node");
  576. // 点击子孙层选中祖父层(递归)
  577. self.selectParents(inp,eleNode,siblingNode);
  578. // 更新选中的数据
  579. self.getCheckedData();
  580. // 数据返回
  581. layui.event.call(inp, "eleTree", 'checkbox('+ self.filter +')', {
  582. data: self.data
  583. ,checkedData: self.checkedData
  584. ,currentData: d
  585. });
  586. })
  587. },
  588. // 拖拽
  589. nodeDrag: function() {
  590. var self=this;
  591. $(this.elem).on("mousedown",".eleTree-node-content",function(e) {
  592. var _self=this;
  593. var time=0;
  594. e.stopPropagation();
  595. $(self.elem).css("user-select","none");
  596. var node=$(this).parent(".eleTree-node ");
  597. var cloneNode=node.clone(true);
  598. var temNode=node.clone(true);
  599. var x=e.clientX-$(self.elem).offset().left;
  600. var y=e.clientY-$(self.elem).offset().top;
  601. $(self.elem).append(cloneNode);
  602. cloneNode.css({
  603. display: "none",
  604. position: "absolute",
  605. "background-color": "#f5f5f5",
  606. width: "100%"
  607. })
  608. $("#tree-menu").hide().remove();
  609. $(document.body).on("mousemove",function(e) {
  610. // t为了区别click事件
  611. time++;
  612. if(time>2){
  613. var xx=e.clientX-$(self.elem).offset().left+10;
  614. var yy=e.clientY-$(self.elem).offset().top-5;
  615. cloneNode.css({
  616. display: "block",
  617. left: xx+"px",
  618. top: yy+"px"
  619. })
  620. }
  621. }).on("mouseup",function(e) {
  622. // dom更改
  623. var groupNode=node.parent(".eleTree-node-group");
  624. cloneNode.remove();
  625. $(self.elem).css("user-select","auto");
  626. $(document.body).off("mousemove").off("mouseup");
  627. var target=$(e.target);
  628. // 数据更改
  629. var dataReset=function(len,childIndex,t) {
  630. // 删除数据
  631. var d=self.reInitData(node);
  632. var parentData=d.parentData.data;
  633. var temData=d.currentData;
  634. var i=d.parentData.childIndex;
  635. if(len===0){
  636. // 判断目标是否超出范围
  637. return false;
  638. }
  639. // 判断当前是否是最外层
  640. if(d.index.length===1){
  641. self.data.splice(d.index[0],1);
  642. }else{
  643. parentData.children.splice(i,1);
  644. parentData.children.length===0 && delete parentData.children;
  645. }
  646. // 如果是同级的,并且从上面的移动到下面,则index减一
  647. var f1=Number(node.attr("eletree-floor"))-1;
  648. var f2=Number(node.attr("eletree-floor"))-1;
  649. if(i<childIndex && node.parents(".eleTree-node[eletree-floor='"+f1+"']").get(0).isEqualNode(t.parents(".eleTree-node[eletree-floor='"+f2+"']").get(0))){
  650. childIndex=childIndex-1;
  651. }
  652. return {
  653. temData: temData,
  654. childIndex: childIndex
  655. };
  656. }
  657. // 判断是否是同一个dom树
  658. var isOwnTarget=target.parents(".eleTree").length===0?target.get(0):target.parents(".eleTree").get(0);
  659. if(!(isOwnTarget.isEqualNode($(self.elem+".eleTree").get(0)))){
  660. return;
  661. }
  662. // 判断目标是否是最外层
  663. if(target.get(0).isEqualNode($(self.elem+".eleTree").get(0))){
  664. var dataRe=dataReset();
  665. var d=dataRe.temData;
  666. self.data.push(d);
  667. node.remove();
  668. // 添加节点
  669. $(self.elem+".eleTree").append(temNode);
  670. // 改floor
  671. temNode.attr("eletree-floor","0");
  672. // 加padding
  673. temNode.children(".eleTree-node-content").css("padding-left","0px");
  674. // 原dom去三角
  675. var leaf=groupNode.children(".eleTree-node").length===0;
  676. leaf && groupNode.siblings(".eleTree-node-content")
  677. .children(".eleTree-node-content-icon").children(".layui-icon-triangle-r")
  678. .removeClass("icon-rotate").css("color","transparent");
  679. // 数据返回
  680. if(time>2){
  681. layui.event.call(_self, "eleTree", 'drag('+ self.filter +')', {
  682. data: self.data
  683. ,currentData: d
  684. });
  685. eleTree.reload(self.elem, {data: self.data});
  686. }
  687. return;
  688. }
  689. // 判断是否不是同一个dom节点或者是其子节点(父节点不能放到子节点)
  690. var t=target;
  691. if(!target.hasClass("eleTree-node-content")){
  692. t=target.parents(".eleTree-node-content");
  693. }
  694. var f=Number(node.attr("eletree-floor"));
  695. var isNotParentsNode=node.get(0).isEqualNode(t.parents("[eletree-floor='"+f+"']").get(0));
  696. if(!isNotParentsNode){
  697. var d=self.reInitData(t.parent(".eleTree-node"));
  698. var i=d.parentData.childIndex;
  699. var dataRe=dataReset(d.index.length,i,t);
  700. var temData=dataRe.temData;
  701. i=dataRe.childIndex;
  702. // 判断目标是否超出范围
  703. if(temData){
  704. node.remove();
  705. // 添加之前先删dom
  706. var parentData=d.parentData.data;
  707. if(d.index.length===1){
  708. parentData.children?parentData.children.push(temData):parentData.children=[temData];
  709. }else{
  710. parentData.children[i].children?parentData.children[i].children.push(temData):parentData.children[i].children=[temData];
  711. }
  712. // 添加节点
  713. target.siblings(".eleTree-node-group").append(temNode);
  714. // 改floor
  715. var floor=Number(target.parent(".eleTree-node").attr("eletree-floor"))+1;
  716. temNode.attr("eletree-floor",String(floor));
  717. // 加padding
  718. temNode.children(".eleTree-node-content").css("padding-left",floor*18+"px");
  719. // 加三角
  720. target.children(".eleTree-node-content-icon").children(".layui-icon-triangle-r")
  721. .addClass("icon-rotate").css("color","#c0c4cc");
  722. // 原dom去三角
  723. var leaf=groupNode.children(".eleTree-node").length===0;
  724. leaf && groupNode.siblings(".eleTree-node-content")
  725. .children(".eleTree-node-content-icon").children(".layui-icon-triangle-r")
  726. .removeClass("icon-rotate").css("color","transparent");
  727. // 数据返回
  728. if(time>2){
  729. layui.event.call(_self, "eleTree", 'drag('+ self.filter +')', {
  730. data: self.data
  731. ,currentData: temData
  732. ,targetData: d.currentData
  733. });
  734. eleTree.reload(self.elem, {data: self.data});
  735. }
  736. }
  737. }
  738. })
  739. })
  740. },
  741. // 初始化checkbox选中状态
  742. checkInit: function(arr,floor) {
  743. var self=this;
  744. $(self.elem+" input[eleTree-status='1']").each(function(index,item) {
  745. var checkboxEl=$(item).siblings(".eleTree-checkbox");
  746. var childNode=checkboxEl.parent(".eleTree-node-content").siblings(".eleTree-node-group").find("input[name='eleTree-node']");
  747. // 选择当前
  748. checkboxEl.addClass("eleTree-checkbox-checked");
  749. checkboxEl.children("i").addClass("layui-icon-ok").removeClass("eleTree-checkbox-line");
  750. // 选择子孙
  751. childNode.prop("checked","checked").attr("eleTree-status","1");
  752. childNode.siblings(".eleTree-checkbox").addClass("eleTree-checkbox-checked");
  753. childNode.siblings(".eleTree-checkbox").children("i").addClass("layui-icon-ok").removeClass("eleTree-checkbox-line");
  754. // 选择祖父
  755. var eleNode=checkboxEl.parent(".eleTree-node-content").parent(".eleTree-node");
  756. var siblingNode=eleNode.siblings(".eleTree-node");
  757. self.selectParents(item,eleNode,siblingNode);
  758. })
  759. },
  760. // 获取选中的数据
  761. getCheckedData: function() {
  762. this.checkedData=[];
  763. var self=this;
  764. $(this.elem+" input[eletree-status='1']").each(function(index,item) {
  765. var node=$(item).parent(".eleTree-node-content").parent(".eleTree-node ");
  766. var d=self.reInitData(node).currentData;
  767. self.checkedData.push(d);
  768. })
  769. return this.checkedData
  770. },
  771. // 通过dom节点找对应数据
  772. reInitData: function(node) {
  773. var i=node.index();
  774. var floor=Number(node.attr("eletree-floor"));
  775. var arr=[]; // 节点对应的index
  776. while (floor>=0) {
  777. arr.push(i);
  778. floor=floor-1;
  779. node=node.parents("[eletree-floor='"+floor+"']");
  780. i=node.index();
  781. }
  782. arr=arr.reverse();
  783. var oData=this.data;
  784. // 当前节点的父节点数据
  785. var parentData=oData[arr[0]];
  786. // 当前节点的data数据
  787. var d = oData[arr[0]];
  788. for(var i = 1; i<arr.length; i++){
  789. d = d["children"]?d["children"][arr[i]]:d;
  790. }
  791. for(var i = 1; i<arr.length-1; i++){
  792. parentData = parentData["children"]?parentData["children"][arr[i]]:parentData;
  793. }
  794. return {
  795. currentData: d,
  796. parentData: {
  797. data: parentData,
  798. childIndex: arr[arr.length-1]
  799. },
  800. index: arr
  801. }
  802. }
  803. }
  804. var thisEleTree=function() {
  805. thisEleTree.o[this.elem] = this;
  806. thisEleTree.config[this.elem] = this.option;
  807. thisEleTree.getCheckedData[this.elem] = this.getCheckedData;
  808. }
  809. // 保存当前对象(为了获取选中元素时改变this指向)
  810. thisEleTree.o = {};
  811. // 保存对象的option
  812. thisEleTree.config = {};
  813. // 获取选中的元素
  814. thisEleTree.getCheckedData = {};
  815. var eleTree={
  816. checkedData: function(elem){
  817. return thisEleTree.getCheckedData[elem].call(thisEleTree.o[elem]);
  818. },
  819. render: function(option) {
  820. var inst=new Class(option);
  821. thisEleTree.call(inst);
  822. },
  823. on: function(events, callback) {
  824. return layui.onevent.call(this, "eleTree", events, callback);
  825. },
  826. reload: function(elem, option) {
  827. var config = thisEleTree.config[elem];
  828. this.render($.extend({}, config, option));
  829. }
  830. }
  831. exports('eleTree',eleTree);
  832. })