/**
* 基于layui的tree重写
* author: hsianglee
* 最近修改时间: 2018/10/27
* 说明:因isEqualNode,ie8不支持拖拽功能
*/
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.drag=this.option.drag;
this.accordion=this.option.accordion;
this.lazy=this.option.lazy;
this.loadData=this.option.loadData;
this.contextmenuList=[];
this.node=""; // 生成树的dom字符串
this.checkedData=[]; // 被选中的数据
this.prevClickEle; // 记录上次点击的dom
this.treeMenu=""; // 右键菜单字符串
this.filter="";
this.isIE8=navigator.appName=="Microsoft Internet Explorer" && navigator.appVersion.split(";")[1].replace(/[ ]/g,"")=="MSIE8.0";
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.lazy && !self.loadData && (function() {
throw "缺少懒加载回调函数";
})()
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.es5ArrMethods();
$(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.contextmenuList.length && this.contextmenuList.length>0 && this.rightClickMenu();
this.checkInit();
},
// 增加foreach,some,every方法支持ie8
es5ArrMethods: function() {
if (!Array.prototype.every) {
Array.prototype.every = function (every_fun, thisArg) {
var _this = null,
iKey = 0,
len = this.length; //无符号右移
if (typeof every_fun !== "function") {
throw new TypeError("every_fun is not a function");
}
if (thisArg) {
_this = thisArg;
}//绑定执行环境
for (; iKey < len; iKey++) {
var key_Value = this[iKey];
if(!every_fun.call(_this, key_Value, iKey, this)){
return false;
};
}
return true;
}
}
if (!Array.prototype.some) {
Array.prototype.some = function (some_fun, thisArg) {
var _this = null,
iKey = 0,
arr_len = this.length;
if (typeof some_fun != 'function') {
throw new typeError('some_fun is not a function')
}
if (thisArg) {
_this = thisArg;
}
for (; iKey < arr_len; iKey++) {
var key_value = this[iKey];
if (some_fun.call(_this, key_value, iKey, this)) {
return true;
}
}
return false;
}
}
if (!Array.prototype.forEach) {
Array.prototype.forEach = function(callback/*, thisArg*/) {
var T, k;
if (this == null) {
throw new TypeError('this is null or not defined');
}
var O = Object(this);
var len = O.length >>> 0; // 所有非数值转换成0,所有大于等于 0 等数取整数部分
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
if (arguments.length > 1) {
T = arguments[1];
}
k = 0;
while (k < len) {
var kValue;
if (k in O) {
kValue = O[k];
callback.call(T, kValue, k, O);
}
k++;
}
};
}
},
// dom生成
nodeInit: function(arr,count,spread) {
// count: 第几层
// spread: 是否不展开
var self=this;
var a=[];
arr.forEach(function(val,index) {
var b=['
'
,'
'
,''
// 判断叶子节点
,(function() {
var fn=function(lazyClassStr) {
if(self.isIE8){
var s=' '
}else{
var s=' '
}
return s;
}
if(val.children && val.children.length>0){
return fn("");
}else if(self.lazy && !val.children && !val.isLeaf){
// 懒加载
return fn("lazy-icon ")
}else{
return ' '
}
})()
,' '
// 判断是否启用checkbox
,(function() {
var s='';
if(self.showCheckbox){
s+=' ';
}
return s;
})()
,''+val.label+' '
,'
'
,'
'
,(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().hide("fast");
if(this.isIE8){
parentSibling.children(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon").removeClass("layui-icon-triangle-d").addClass("layui-icon-triangle-r");
}else{
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",function(e) {
e.stopPropagation();
// 添加active背景
if(self.prevClickEle) self.prevClickEle.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;
// 切换下拉
var el=$(this).children(".eleTree-node-content-icon").children(".layui-icon");
if(self.isIE8) {
// ie8
if(el.hasClass("layui-icon-triangle-d")){
// 合并
$(this).siblings(".eleTree-node-group").children().hide("fast");
el.removeClass("layui-icon-triangle-d").addClass("layui-icon-triangle-r");
// 数据修改
delete d.spread;
}else{
// 展开
// 懒加载数据
if(self.lazy && el.hasClass("lazy-icon")){
el.removeClass("layui-icon-triangle-r").addClass("layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop");
self.loadData(d,function(childrenData) {
d.children=childrenData;
self.render();
})
}
$(this).siblings(".eleTree-node-group").children().show("fast");
el.addClass("layui-icon-triangle-d").removeClass("layui-icon-triangle-r");
// 数据修改
d.spread=true;
self.accordionFn($(this),data);
}
}else{
if(el.hasClass("icon-rotate")){
// 合并
$(this).siblings(".eleTree-node-group").children().hide("fast");
el.removeClass("icon-rotate");
// 数据修改
delete d.spread;
}else{
// 展开
// 懒加载数据
if(self.lazy && el.hasClass("lazy-icon")){
el.removeClass("layui-icon-triangle-r icon-rotate").addClass("layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop");
self.loadData(d,function(childrenData) {
d.children=childrenData;
self.render();
})
}
$(this).siblings(".eleTree-node-group").children().show("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();
});
},
// 右键菜单
rightClickMenu: function() {
var self=this;
var menuStr=[''].join("");
this.treeMenu=$(menuStr);
$(this.elem).on("contextmenu",".eleTree-node-content",function(e) {
var _self=this;
e.stopPropagation();
e.preventDefault();
// 添加active背景
if(self.prevClickEle) self.prevClickEle.removeClass("eleTree-node-content-active");
$(this).addClass("eleTree-node-content-active");
// 菜单位置
$(document.body).after(self.treeMenu);
$("#tree-menu").css({
left: e.pageX,
top: e.pageY
}).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() {
layer.prompt({title: "请输入label值"},function(value, index, elem){
// 判断当前是否选中,若选中,则新增的子元素也应该选中
var isChecked=$(_self).children(".eleTree-hideen").attr("eletree-status")==="1";
// 数据修改
var node=$(_self).parent(".eleTree-node ");
var data=self.reInitData(node);
var d=data.currentData;
d.children?"":d.children=[];
var obj={
label: value
}
isChecked?obj.checked=true:"";
d.children.push(obj);
d.spread=true;
self.accordionFn($(_self),data);
// 数据返回
layui.event.call(_self, "eleTree", 'add('+ self.filter +')', {
value: value
,data: self.data
,currentData: d
});
// dom修改
var floor=Number($(_self).parent(".eleTree-node").attr("eletree-floor"))+1;
var isLeaf=$(_self).siblings(".eleTree-node-group").children(".eleTree-node").length===0;
isLeaf && $(_self).children(".eleTree-node-content-icon").children("i").css("color","#c0c4cc").addClass("icon-rotate");
var s=[''
,'
'
,''
,' '
,' '
// 判断是否启用checkbox
,(function() {
var s="";
if(self.showCheckbox){
s+=' '
}
return s;
})()
,''+value+' '
,'
'
,'
'
,'
'
,'
'].join("");
$(_self).siblings(".eleTree-node-group").append(s);
// checkbox解析
var inp=$(_self).siblings(".eleTree-node-group").children(".eleTree-node:last").children(".eleTree-node-content").children("input.eleTree-hideen[type=checkbox]");
var checkStr=['
'].join("");
inp.after(checkStr);
layer.close(index);
});
});
// 编辑
$("#tree-menu li.edit").off().on("click",function() {
layer.prompt({
value: $(_self).children(".eleTree-node-content-label").text(),
title: '请输入修改的label值'
},function(value, index, elem){
// 数据修改
var node=$(_self).parent(".eleTree-node ");
var d=self.reInitData(node).currentData;
d.label=value;
// 数据返回
layui.event.call(_self, "eleTree", 'edit('+ self.filter +')', {
value: value
,data: self.data
,currentData: d
});
// dom修改
$(_self).children(".eleTree-node-content-label").text(value);
layer.close(index);
});
});
// 删除
$("#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;
// 最外层判断
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: self.data
,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");
});
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(i2){
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