/**
* 基于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 += '';
}
return s;
})()
, (function () {
if (self.showIcon) {
return '' + val.icon + ''
}
})()
, (function () {
if (self.menuShow) {
return '' + val.name + ''
} else {
return '' + val.areaName + ''
}
})()
, (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);
})