/** * 基于layui的tree重写 * author: hsianglee * 最近修改时间: 2018/09/26 */ layui.define(["jquery", "laytpl", "layer", "form"], function (exports) { var $ = layui.jquery; var laytpl = layui.laytpl; var layer = layui.layer; var form = layui.form; function Class(option) { this.option = option; // 获取传入的数据 this.elem = ""; this.data = []; this.showCheckbox = this.option.showCheckbox; this.showIcon = this.option.showIcon; this.drag = this.option.drag; this.accordion = this.option.accordion; this.contextmenuList = []; this.node = ""; // 生成树的dom字符串 this.checkedData = []; // 被选中的数据 this.prevClickEle; // 记录上次点击的dom this.treeMenu = ""; // 右键菜单字符串 this.filter = ""; this.menuShow = this.option.menuShow; this.open = this.option.open; this.render(); } Class.prototype = { constructor: Class, // 初始化参数数据 render: function () { var self = this; self.option.elem ? (function () { self.elem = self.option.elem; })() : (function () { throw "缺少elem节点选择器"; })(); self.contextmenuList = self.option.contextmenuList ? self.option.contextmenuList : []; self.filter = $(self.elem).attr("lay-filter"); // 判断data参数 if (self.option.data) { self.data = self.option.data; self.init(); return; } // 判断url参数 if (self.option.url) { $.ajax({ url: self.option.url, type: self.option.type ? self.option.type : "get", data: self.option.where ? self.option.where : {}, success: function (data) { if (data.code === 0) { self.data = data.data; self.init(); return; } layer.alert(data.Msg, { title: "选择器" + self.elem + "获取数据失败", icon: 2 }); } }); return; } throw "选择器" + self.elem + "缺少data或url参数"; }, // 初始化容器和标签 init: function () { var self = this; this.node = ""; $(this.elem).empty(); $(this.elem).off(); this.nodeInit(this.data, 0, false); $(this.elem).html(this.node); this.checkboxEvent(); // 更新选中的数据 this.getCheckedData(); this.drag && this.nodeDrag(); this.eleTreeEvent(); this.eleTreeClick(); this.contextmenuList.length && this.contextmenuList.length > 0 && this.rightClickMenu(); this.checkInit(); }, // dom生成 nodeInit: function (arr, count, spread) { // count: 第几层 // spread: 是否不展开 var self = this; var a = []; arr.forEach(function (val, index) { var b = ['
' , '
' , '' // 判断叶子节点 , (function () { if (val.children && val.children.length > 0) { var s = '' return s; } else { return '' } })() , '' // 判断是否启用checkbox , (function () { var s = ''; if (self.showCheckbox) { s += '' + val.icon + '' } })() , (function () { if (self.menuShow) { return '' } else { return '' } })() , (function () { if (val.status == 2) { return '' } })() , (function () { if (val.status == 1) { return '' } })() , '
' , '
' , (function () { if (val.children && val.children.length > 0) { return self.nodeInit(val.children, count + 1, !val.spread); // 获取已经遍历完的子节点 } })() , '
' , '
']; a = a.concat(b); }, this); this.node = a.join(""); return this.node; // 返回已经遍历完的子节点 }, // 手风琴效果 accordionFn: function (ele, d) { if (!this.accordion) return; // 手风琴 var parentSibling = ele.parent(".eleTree-node").siblings(".eleTree-node"); parentSibling.children(".eleTree-node-group").children().slideUp("fast"); parentSibling.children(".eleTree-node-content").find(".layui-icon-triangle-r").removeClass("icon-rotate"); var parentData = d.parentData; // 最外层判断 if (d.index.length === 1) { this.data.forEach(function (val, index) { if (index !== parentData.childIndex) { delete val.spread; } }) } else { parentData.data.children.forEach(function (val, index) { if (index !== parentData.childIndex) { delete val.spread; } }) } }, // 展开合并动画 eleTreeEvent: function () { var self = this; $(this.elem).on("click", ".eleTree-node-content-icon", function (e) { e.stopPropagation(); // 获取点击所在数据 var node = $(this).parents(".eleTree-node "); var data = self.reInitData(node); var d = data.currentData; // 切换下拉 var el = $(this).find(".layui-icon-triangle-r"); if (el.hasClass("icon-rotate")) { $(this).parent(".eleTree-node-content").siblings(".eleTree-node-group").children().slideUp("fast"); el.removeClass("icon-rotate"); // 数据修改 delete d.spread; } else { $(this).parent(".eleTree-node-content").siblings(".eleTree-node-group").children().slideDown("fast"); el.addClass("icon-rotate"); // 数据修改 d.spread = true; self.accordionFn($(this), data); } self.prevClickEle = $(this); // 数据返回 layui.event.call(this, "eleTree", 'toggleSlide(' + self.filter + ')', { data: self.data , currentData: d }); $("#tree-menu").hide().remove(); }); $(document).on("click", function () { $("#tree-menu").hide().remove(); }); }, // 单击动画 eleTreeClick: function () { var self = this; $(this.elem).on("click", ".eleTree-node-content", function (e) { if ($(this).find(".layui-lock").length > 0) { ; return true } e.stopPropagation(); // 添加active背景 $(".eleTree-node-content").removeClass("eleTree-node-content-active"); $(this).addClass("eleTree-node-content-active"); // 获取点击所在数据 var node = $(this).parent(".eleTree-node "); var data = self.reInitData(node); var d = data.currentData; // 数据返回 layui.event.call(this, "eleTree", 'click(' + self.filter + ')', { currentData: d }); $("#tree-menu").hide().remove(); }); $(document).on("click", function () { $("#tree-menu").hide().remove(); }); }, // 右键菜单 rightClickMenu: function () { var self = this; var menuStr = [''].join(""); this.treeMenu = $(menuStr); $(this.elem).on("contextmenu", ".eleTree-node-content", function (e) { if ($(this).find(".eleTree-node-content-btn").length > 0) { ; return true } var _self = this; e.stopPropagation(); e.preventDefault(); // 添加active背景 $(".eleTree-node-content").removeClass("eleTree-node-content-active"); if (self.prevClickEle) self.prevClickEle.removeClass("eleTree-node-content-active"); $(this).addClass("eleTree-node-content-active"); // 菜单位置 $(self.elem).after(self.treeMenu); $("#tree-menu").css({ left: e.pageX + 10, top: e.pageY - 30, }).show(); // 复制 $("#tree-menu li.copy").off().on("click", function () { var el = $(_self).children(".eleTree-node-content-label").get(0); var selection = window.getSelection(); var range = document.createRange(); range.selectNodeContents(el); selection.removeAllRanges(); selection.addRange(range); document.execCommand('Copy', 'false', null); selection.removeAllRanges(); }); // 新增 $("#tree-menu li.add").off().on("click", function () { var node = $(_self).parent(".eleTree-node "); var data = self.reInitData(node); var d = data.parentData.data; // 数据返回 layui.event.call(_self, "eleTree", 'add(' + self.filter + ')', { data: data.currentData, parentData: d }); }); // 删除 $("#tree-menu li.remove").off().on("click", function () { // 数据删除 var node = $(_self).parent(".eleTree-node "); var data = self.reInitData(node); var d = data.parentData.data; var arr = data.index; console.log(data) // 最外层判断 if (arr.length === 1) { self.data.splice(arr[arr.length - 1], 1); } else { if (d["children"]) { d["children"].splice(arr[arr.length - 1], 1); d["children"].length === 0 && delete d["children"]; } } // 数据返回 layui.event.call(_self, "eleTree", 'remove(' + self.filter + ')', { data: data.currentData , parentData: d }); // dom删除 var tem = $(_self).parent(".eleTree-node").parent(".eleTree-node-group"); //$(_self).parent(".eleTree-node").remove(); var isLeaf = tem.children(".eleTree-node").length === 0; isLeaf && tem.siblings(".eleTree-node-content").children(".eleTree-node-content-icon").children("i").css("color", "transparent").removeClass("icon-rotate"); }); // 禁用 $("#tree-menu li.forbid").off().on("click", function () { // 数据删除 var node = $(_self).parent(".eleTree-node "); var data = self.reInitData(node); var d = data.parentData.data; var arr = data.index; // 最外层判断 if (arr.length === 1) { self.data.splice(arr[arr.length - 1], 1); } else { if (d["children"]) { d["children"].splice(arr[arr.length - 1], 1); d["children"].length === 0 && delete d["children"]; } } // 数据返回 layui.event.call(_self, "eleTree", 'forbid(' + self.filter + ')', { data: data.currentData, parentData: d }); // dom禁止 var tem = $(_self).parent(".eleTree-node").parent(".eleTree-node-group"); var isLeaf = tem.children(".eleTree-node").length === 0; isLeaf && tem.siblings(".eleTree-node-content").children(".eleTree-node-content-icon").children("i").css("color", "transparent").removeClass("icon-rotate"); }); self.prevClickEle = $(this); }) }, // 自定义checkbox解析 checkboxRender: function () { $(this.elem).find(this.elem + " .eleTree-checkbox").remove(); $(this.elem + " input.eleTree-hideen[type=checkbox]").each(function (index, item) { if ($(item).hasClass("eleTree-disabled")) { $(item).after('
'); } else { $(item).after('
'); } }) }, // 通过子孙选中祖父(递归) selectParents: function (inp, eleNode, siblingNode) { // inp: 实际input(dom元素) // eleNode: input父层类(.eleTree-node) // siblingNode: 父层同级兄弟 while (Number(eleNode.attr("eletree-floor")) !== 0) { // 同级input状态存入数组 var arr = []; arr.push($(inp).attr("eleTree-status")); siblingNode.each(function (index, item) { var siblingIsChecked = $(item).children(".eleTree-node-content").children("input[name='eleTree-node']").attr("eleTree-status"); arr.push(siblingIsChecked); }) // 父元素的实际input var parentInput = eleNode.parent(".eleTree-node-group").siblings(".eleTree-node-content").children("input[name='eleTree-node']"); // 父元素的checkbox替代 var parentCheckbox = parentInput.siblings(".eleTree-checkbox"); // 父元素的icon var parentIcon = parentCheckbox.children("i"); if (arr.every(function (val) { return val === "1"; })) { // 子都选中则选中父 parentInput.prop("checked", "checked").attr("eleTree-status", "1"); parentCheckbox.addClass("eleTree-checkbox-checked"); parentIcon.addClass("layui-icon-ok").removeClass("eleTree-checkbox-line"); } if (arr.some(function (val) { return val === "0" || val === "2"; })) { // 子有一个未选中则checkbox第三种状态 // parentInput.prop("checked","checked"); parentInput.attr("eleTree-status", "2"); parentCheckbox.addClass("eleTree-checkbox-checked"); parentIcon.removeClass("layui-icon-ok").addClass("eleTree-checkbox-line"); } if (arr.every(function (val) { return val === "0"; })) { // 子全部未选中则取消父选中(并且取消第三种状态) parentInput.removeAttr("checked"); parentInput.attr("eleTree-status", "0"); parentCheckbox.removeClass("eleTree-checkbox-checked"); parentIcon.removeClass("layui-icon-ok eleTree-checkbox-line"); } var parentNode = eleNode.parents("[eletree-floor='" + (Number(eleNode.attr("eletree-floor")) - 1) + "']"); var parentCheckbox = parentNode.children(".eleTree-node-content").children("input[name='eleTree-node']").get(0); var parentSiblingNode = parentNode.siblings(".eleTree-node"); eleNode = parentNode; inp = parentCheckbox; siblingNode = parentSiblingNode; } }, // checkbox添加选中事件 checkboxEvent: function () { var self = this; this.checkboxRender(); // input添加属性eleTree-status:即input的三种状态,"0":未选中,"1":选中,"2":子孙部分选中 $(this.elem).on("click", ".eleTree-checkbox", function (e) { e.stopPropagation(); if ($(this).hasClass("eleTree-checkbox-disabled")) return; // 获取点击所在数据 var node = $(this).parent(".eleTree-node-content").parent(".eleTree-node "); var d = self.reInitData(node).currentData; // 实际的input var inp = $(this).siblings(".eleTree-hideen").get(0); if (inp.checked) { $(inp).removeAttr("checked").attr("eleTree-status", "0"); $(this).removeClass("eleTree-checkbox-checked"); $(this).children("i").removeClass("layui-icon-ok eleTree-checkbox-line"); // 数据更新 delete d.checked; } else { $(inp).prop("checked", "checked").attr("eleTree-status", "1"); $(this).addClass("eleTree-checkbox-checked"); $(this).children("i").addClass("layui-icon-ok").removeClass("eleTree-checkbox-line"); d.checked = true; } var childNode = $(inp).parent(".eleTree-node-content").siblings(".eleTree-node-group").find("input[name='eleTree-node']"); // 点击祖父层选中子孙层 inp.checked ? (function () { childNode.prop("checked", "checked").attr("eleTree-status", "1"); childNode.siblings(".eleTree-checkbox").addClass("eleTree-checkbox-checked"); childNode.siblings(".eleTree-checkbox").children("i").addClass("layui-icon-ok").removeClass("eleTree-checkbox-line"); })() : (function () { childNode.removeAttr("checked"); childNode.attr("eleTree-status", "0"); childNode.siblings(".eleTree-checkbox").removeClass("eleTree-checkbox-checked"); childNode.siblings(".eleTree-checkbox").children("i").removeClass("layui-icon-ok eleTree-checkbox-line"); })(); var eleNode = $(inp).parent(".eleTree-node-content").parent(".eleTree-node"); var siblingNode = eleNode.siblings(".eleTree-node"); // 点击子孙层选中祖父层(递归) self.selectParents(inp, eleNode, siblingNode); // 更新选中的数据 self.getCheckedData(); // 数据返回 layui.event.call(inp, "eleTree", 'checkbox(' + self.filter + ')', { data: self.data , checkedData: self.checkedData , currentData: d }); }) }, // 拖拽 nodeDrag: function () { var self = this; $(this.elem).on("mousedown", ".eleTree-node-content", function (e) { var _self = this; var time = 0; e.stopPropagation(); $(self.elem).css("user-select", "none"); var node = $(this).parent(".eleTree-node "); var cloneNode = node.clone(true); var temNode = node.clone(true); var x = e.clientX - $(self.elem).offset().left; var y = e.clientY - $(self.elem).offset().top; $(self.elem).append(cloneNode); cloneNode.css({ display: "none", position: "absolute", "background-color": "#f5f5f5", width: "100%" }) $("#tree-menu").hide().remove(); $(document.body).on("mousemove", function (e) { // t为了区别click事件 time++; if (time > 2) { var xx = e.clientX - $(self.elem).offset().left + 10; var yy = e.clientY - $(self.elem).offset().top - 5; cloneNode.css({ display: "block", left: xx + "px", top: yy + "px" }) } }).on("mouseup", function (e) { // dom更改 var groupNode = node.parent(".eleTree-node-group"); cloneNode.remove(); $(self.elem).css("user-select", "auto"); $(document.body).off("mousemove").off("mouseup"); var target = $(e.target); // 数据更改 var dataReset = function (len, childIndex, t) { // 删除数据 var d = self.reInitData(node); var parentData = d.parentData.data; var temData = d.currentData; var i = d.parentData.childIndex; if (len === 0) { // 判断目标是否超出范围 return false; } // 判断当前是否是最外层 if (d.index.length === 1) { self.data.splice(d.index[0], 1); } else { parentData.children.splice(i, 1); parentData.children.length === 0 && delete parentData.children; } // 如果是同级的,并且从上面的移动到下面,则index减一 var f1 = Number(node.attr("eletree-floor")) - 1; var f2 = Number(node.attr("eletree-floor")) - 1; if (i < childIndex && node.parents(".eleTree-node[eletree-floor='" + f1 + "']").get(0).isEqualNode(t.parents(".eleTree-node[eletree-floor='" + f2 + "']").get(0))) { childIndex = childIndex - 1; } return { temData: temData, childIndex: childIndex }; } // 判断是否是同一个dom树 var isOwnTarget = target.parents(".eleTree").length === 0 ? target.get(0) : target.parents(".eleTree").get(0); if (!(isOwnTarget.isEqualNode($(self.elem + ".eleTree").get(0)))) { return; } // 判断目标是否是最外层 if (target.get(0).isEqualNode($(self.elem + ".eleTree").get(0))) { var dataRe = dataReset(); var d = dataRe.temData; self.data.push(d); node.remove(); // 添加节点 $(self.elem + ".eleTree").append(temNode); // 改floor temNode.attr("eletree-floor", "0"); // 加padding temNode.children(".eleTree-node-content").css("padding-left", "0px"); // 原dom去三角 var leaf = groupNode.children(".eleTree-node").length === 0; leaf && groupNode.siblings(".eleTree-node-content") .children(".eleTree-node-content-icon").children(".layui-icon-triangle-r") .removeClass("icon-rotate").css("color", "transparent"); // 数据返回 if (time > 2) { layui.event.call(_self, "eleTree", 'drag(' + self.filter + ')', { data: self.data , currentData: d }); eleTree.reload(self.elem, { data: self.data }); } return; } // 判断是否不是同一个dom节点或者是其子节点(父节点不能放到子节点) var t = target; if (!target.hasClass("eleTree-node-content")) { t = target.parents(".eleTree-node-content"); } var f = Number(node.attr("eletree-floor")); var isNotParentsNode = node.get(0).isEqualNode(t.parents("[eletree-floor='" + f + "']").get(0)); if (!isNotParentsNode) { var d = self.reInitData(t.parent(".eleTree-node")); var i = d.parentData.childIndex; var dataRe = dataReset(d.index.length, i, t); var temData = dataRe.temData; i = dataRe.childIndex; // 判断目标是否超出范围 if (temData) { node.remove(); // 添加之前先删dom var parentData = d.parentData.data; if (d.index.length === 1) { parentData.children ? parentData.children.push(temData) : parentData.children = [temData]; } else { parentData.children[i].children ? parentData.children[i].children.push(temData) : parentData.children[i].children = [temData]; } // 添加节点 target.siblings(".eleTree-node-group").append(temNode); // 改floor var floor = Number(target.parent(".eleTree-node").attr("eletree-floor")) + 1; temNode.attr("eletree-floor", String(floor)); // 加padding temNode.children(".eleTree-node-content").css("padding-left", floor * 18 + "px"); // 加三角 target.children(".eleTree-node-content-icon").children(".layui-icon-triangle-r") .addClass("icon-rotate").css("color", "#c0c4cc"); // 原dom去三角 var leaf = groupNode.children(".eleTree-node").length === 0; leaf && groupNode.siblings(".eleTree-node-content") .children(".eleTree-node-content-icon").children(".layui-icon-triangle-r") .removeClass("icon-rotate").css("color", "transparent"); // 数据返回 if (time > 2) { layui.event.call(_self, "eleTree", 'drag(' + self.filter + ')', { data: self.data , currentData: temData , targetData: d.currentData }); eleTree.reload(self.elem, { data: self.data }); } } } }) }) }, // 初始化checkbox选中状态 checkInit: function (arr, floor) { var self = this; $(self.elem + " input[eleTree-status='1']").each(function (index, item) { var checkboxEl = $(item).siblings(".eleTree-checkbox"); var childNode = checkboxEl.parent(".eleTree-node-content").siblings(".eleTree-node-group").find("input[name='eleTree-node']"); // 选择当前 checkboxEl.addClass("eleTree-checkbox-checked"); checkboxEl.children("i").addClass("layui-icon-ok").removeClass("eleTree-checkbox-line"); // 选择子孙 childNode.prop("checked", "checked").attr("eleTree-status", "1"); childNode.siblings(".eleTree-checkbox").addClass("eleTree-checkbox-checked"); childNode.siblings(".eleTree-checkbox").children("i").addClass("layui-icon-ok").removeClass("eleTree-checkbox-line"); // 选择祖父 var eleNode = checkboxEl.parent(".eleTree-node-content").parent(".eleTree-node"); var siblingNode = eleNode.siblings(".eleTree-node"); self.selectParents(item, eleNode, siblingNode); }) }, // 获取选中的数据 getCheckedData: function () { this.checkedData = []; var self = this; $(this.elem + " input[eletree-status='1']").each(function (index, item) { var node = $(item).parent(".eleTree-node-content").parent(".eleTree-node "); var d = self.reInitData(node).currentData; self.checkedData.push(d); }); return this.checkedData }, // 通过dom节点找对应数据 reInitData: function (node) { var i = node.index(); var floor = Number(node.attr("eletree-floor")); var arr = []; // 节点对应的index while (floor >= 0) { arr.push(i); floor = floor - 1; node = node.parents("[eletree-floor='" + floor + "']"); i = node.index(); } arr = arr.reverse(); var oData = this.data; // 当前节点的父节点数据 var parentData = oData[arr[0]]; // 当前节点的data数据 var d = oData[arr[0]]; for (var i = 1; i < arr.length; i++) { d = d["children"] ? d["children"][arr[i]] : d; } for (var i = 1; i < arr.length - 1; i++) { parentData = parentData["children"] ? parentData["children"][arr[i]] : parentData; } return { currentData: d, parentData: { data: parentData, childIndex: arr[arr.length - 1] }, index: arr } }, } var thisEleTree = function () { thisEleTree.o[this.elem] = this; thisEleTree.config[this.elem] = this.option; thisEleTree.getCheckedData[this.elem] = this.getCheckedData; } // 保存当前对象(为了获取选中元素时改变this指向) thisEleTree.o = {}; // 保存对象的option thisEleTree.config = {}; // 获取选中的元素 thisEleTree.getCheckedData = {}; var eleTree = { checkedData: function (elem) { return thisEleTree.getCheckedData[elem].call(thisEleTree.o[elem]); }, render: function (option) { var inst = new Class(option); thisEleTree.call(inst); }, on: function (events, callback) { return layui.onevent.call(this, "eleTree", events, callback); }, reload: function (elem, option) { var config = thisEleTree.config[elem]; this.render($.extend({}, config, option)); } } exports('eleTree', eleTree); })