最近项目选项前端技术选型选择了LayUI,没选到的是tree组件的功能实在太弱了,没办了,只能自己修改了源码,目前实现了以下功能,github还没有时间更新敬请期待。那我们来看看扩展功能吧:
一、扩展功能
1,增加了目录树的搜索功能
2,增加了目录树的复选框和事件回调的实现
3,增加了根节点图标和叶子图标自定义设置。
4,增加右键菜单和事件回调。
让我妈看一下效果图吧
二、让我看一下实现源码吧
调用方式
layui.use(['tree', 'layer'], function () {
var layer = layui.layer
, $ = layui.jquery
, tree = layui.tree;
// 同步(绑定)layui的tree的搜索(过滤)框
// treeId: tree所在的容器的id
// filter: 对应的搜索框的selector或者dom对象,尽量要确保是唯一的节点,或者真的是要控制这个树的input
// callback: 回调 参数(树节点jquery对象, 输入框对象, 匹配到的节点数量)
tree.syncLayuiTreeFilter = function (treeId, filter, callback) {
var treeElem = $('#' + treeId), filterElem = $(filter);
if (!filterElem.length || !filterElem.length) {
return;
}
filterElem.keyup(
function (event) {
var that = this;
var value = $(that).val().trim().toLocaleLowerCase();//不区分大小写
var HIDE = 'layui-hide';
var hintClass = 'search_hit';
// 先恢复现场
treeElem.find('.' + HIDE).removeClass(HIDE);
treeElem.find('.' + hintClass).removeClass(hintClass).each(function (index, item) {
item = $(item);
item.html(item.data('textOld')).data('textOld', null);
});
// 如果有值筛选开始
if (value) {
layui.each(treeElem.find('cite'), function (index, elem) {
elem = $(elem);
var textTemp = elem.text();
if (textTemp.toLocaleLowerCase().indexOf(value) === -1) { //不区分大小写
// 不存在就隐藏
elem.closest('li').addClass(HIDE);
} else {
// 命中就添加一个class
elem.addClass(hintClass)
.data('textOld', textTemp)
.html(textTemp.replace(new RegExp(value, 'g'), '' + value + ''));
}
});
layui.each(treeElem.find('.' + hintClass), function (index, elem) {
elem = $(elem);
elem.parents('li').removeClass(HIDE);
elem.parents('ul').each(function (i, item) {
if (!$(item).hasClass('layui-show')) {
$(item).parent('li').find('>i').click();
}
});
elem.parents('ul').parent('li').removeClass(HIDE);
});
}
typeof callback === 'function' && callback.call(that, treeElem, filterElem, treeElem.find('.' + hintClass).length);
}
);
};
tree({
elem: '#layTree' //指定元素
,branchExtent:["Ico_fold","Ico_launch"] //树形折叠图标第一个是折叠样式,第二个展开样式
,target: '_blank' //是否新选项卡打开(比如节点返回href才有效)
,check: 'checkbox'
,checkboxName: 'ck'//复选框的name属性值
,checkboxStyle: ""
,drag: true
, nodes: [ //节点
{
name: '常用文件夹'
,id: 1
,alias: 'changyong'
,checked: true
,data:{
text:123,//data-text 用于存储数据
ceshi:456}
, children: [
{
name: '所有未读'
, id: 11
, href: 'http://www.layui.com/'
, alias: 'weidu'
, checked: true
,leaf:"Ico_point1" //css样式
,data:{}
},
{
name: '置顶邮件'
,id: 12
,leaf:"Ico_point2"
,data:{}
}, {
name: '邮件标签邮件'
,id: 13
,leaf:"Ico_point3"
,data:{}
,children: [
{
name: '所有未读'
, id: 11
, href: 'http://www.layui.com/'
, alias: 'weidu'
, checked: true
, leaf:"Ico_point1" //css样式
,data:{}
},
{
name: '置顶邮件'
,id: 12
,leaf:"Ico_point2"
,data:{}
}, {
name: '邮件标签邮件'
,id: 13
,leaf:"Ico_point3"
,data:{}
}
]
}
]
}
]
,click: function(node){
console.log(node) //node即为当前点击的节点数据
var as= $("#layTree").find('a');
$.each(as,function (index,obj) {
if($(obj).children("cite").text()=='置顶邮件') {
console.log($(obj).parent());
$(obj).parent().append("");
//element.init();
// tree.render();
return false;
}
})
},
onchange: function (event,item){//当当前input发生变化后所执行的回调
console.log(item); //item即为当前点击的节点数据
console.log(event); //事件源
}
,rightClick:function(event,elem) {
console.log("你的鼠标右击了我!"+elem);
console.log(elem);
event.preventDefault();
return false;
}
});
tree.syncLayuiTreeFilter('layTree', '[name="searchTree"]', function (treeElem, filterElem, hitNumbers) {
console.log('hitNumbers', hitNumbers);
layer.msg('找到' + hitNumbers + '个节点');
});
tree.js 源码
//扩展日志 author:wangxianyang
//1,增加复选框并且加上了事件回调和参数传递
//2,增加了折叠图标和叶子图标的自定义扩展
//3,增加了右击菜单事件和参数传递
//4,增加了tree的搜索功能(模糊匹配不区分大小写)
;
layui.define("jquery",
function(e) {
"use strict";
var o = layui.jquery,
a = layui.hint(),
r = "layui-tree-enter",
i = function(e) {
this.options = e
},
t = {
arrow: ["", ""],
checkbox: ["", ""],
radio: ["", ""],
branch: ["", ""],
leaf: ""
},
branchExtent,//折叠图标扩展
leafExtent="",//叶子图标扩展
leftClick=true,
num = 1;
i.prototype.init = function(e) {
var o = this;
branchExtent=o.options.branchExtent||["",""];
e.addClass("layui-box layui-tree"),
o.options.skin && e.addClass("layui-tree-skin-" + o.options.skin),
o.tree(e),
o.on(e)
//e.preventDefault();
false;
},
i.prototype.tree = function(e, a) {
var r = this,
i = r.options,
n = a || i.nodes;
layui.each(n,
function(a, n) {
var id = r.uuid();
n.id = id;
//console.log(n.data);
if (n.children) {
layui.each(n.children,
function(index, item) {
item.pid = n.id;
});
}
var l = n.children && n.children.length > 0,
c = o('
'),
s = o(["",
function() {
return l ? '' + (n.spread ? t.arrow[1] : t.arrow[0]) + '': '';
} (),
function() {
var eleStr = i.check && i.check == "checkbox" ? ' 0) {
if (n.data && Object.prototype.toString.call(n.data) == "[object Object]") {
for (var attr in n.data) {
eleStr += ' data-' + attr + '=' + n.data[attr];
}
}
eleStr += ' />';
}
return eleStr;
} (),
function() {
//debugger;
//return '" + ('' + (l ? n.spread ? t.branch[1] : t.branch[0] : t.leaf) + "") + ("" + (n.name || "未命名") + "")
return '"
+ (''
+ "") + ("" + (n.name || "未命名") + "")
} (), " "].join(""));
l && (s.append(c), r.tree(c, n.children)),e.append(s), "function" == typeof i.click && r.click(s, n),r.spread(s, n), i.drag && r.drag(s, n) , i.onchange && r.changed(s, n) //注册复选框事件
})
},
i.prototype.changed = function(e, o) {
var r = this;
if (o.pid == undefined || o.pid == null) {
e.children("input").on("change",
function() {
var childUl = e.children("ul"),
checked = this.checked;
childUl.find("input").prop("checked", checked);
try {
// debugger;
r.options.onchange((e.children("input").prop("checked") || false), o);
} catch(e) {}
});
} else {
e.children("input").on("change",
function() {
var that = this;
if (!this.checked) {
childCheckboxCheckOrNot.call(this);
r.cancelParentsCheckboxCheck(that);
} else {
r.parentsChecked(this, this.checked);
childCheckboxCheckOrNot.call(this);
}
try {
//debugger;
r.options.onchange((e.children("input").prop("checked") || false), o);
} catch(e) {}
});
}
function childCheckboxCheckOrNot() {
if (o.children && o.children.length > 0) {
var childUl = e.children("ul"),
checked = this.checked;
childUl.find("input").prop("checked", checked);
}
}
},
i.prototype.cancelParentsCheckboxCheck = function(ele) {
if (!ele) {
return;
}
var r = this,
siblingInputs = r.siblingInputs(ele),
parentId = ele.getAttribute("data-parent-id"),
parentInput = null,
bool = true,
childrendInputs = null,
hasOneChildrenInputCheck = false;
if (parentId != 'undefined') {
parentInput = document.getElementById(parentId);
childrendInputs = r.currentChildrenInputs(parentInput);
}
for (var i = 0,
len = siblingInputs.length; i < len; i++) {
if (siblingInputs[i].checked) {
bool = false;
break;
}
}
if (!childrendInputs || childrendInputs.length == 0) {
hasOneChildrenInputCheck = false;
} else {
for (var j = 0,
len2 = childrendInputs.length; j < len2; j++) {
if (childrendInputs[j].getAttribute("data-parent-id") != "undefined") {
if (childrendInputs[j].checked) {
hasOneChildrenInputCheck = true;
break;
}
}
}
}
if (bool && !hasOneChildrenInputCheck) {
r.inputChecked(parentInput, false);
}
this.cancelParentsCheckboxCheck(parentInput);
},
i.prototype.siblingInputs = function(ele) {
var that = this;
if (ele) {
var parent = ele.parentElement,
parents = parent.parentElement,
childrens = parents.children,
siblingInputs = [];
} else {
return null;
}
for (var i = 0,
len = childrens.length; i < len; i++) {
if (childrens[i] != parent) {
if (childrens[i].children[0].nodeName == "INPUT") {
siblingInputs.push(childrens[i].children[0]);
}
if (childrens[i].children[1].nodeName == "INPUT") {
siblingInputs.push(childrens[i].children[1]);
}
}
}
parent = null;
parents = null;
childrens = null;
return siblingInputs;
},
i.prototype.currentChildrenInputs = function(ele) {
var parent = ele.parentElement,
childrenInputs = [];
if (parent.getElementsByTagName("ul").length > 0) {
var uls = parent.getElementsByTagName("ul");
for (var i = 0,
len = uls.length; i < len; i++) {
var inputs = uls[i].getElementsByTagName("input");
for (var j = 0,
len2 = inputs.length; j < len2; j++) {
childrenInputs.push(inputs[j]);
}
}
}
return childrenInputs;
},
i.prototype.inputChecked = function(ele, checked) {
ele && (ele.checked = checked);
},
i.prototype.parentsChecked = function(e, checked) {
var r = this,
i = r.options,
selector = i.elem,
currentInput = e;
if (currentInput && (currentInput.nodeName == "INPUT")) {
var parentId = currentInput.getAttribute("data-parent-id"),
parentInput = null;
setTimeout(function() {
r.inputChecked(currentInput, checked);
if (parentId) {
r.parentsChecked(document.getElementById(parentId), checked);
}
},
50);
}
},
i.prototype.findParents = function(ele, selector) {
var parent = ele.parentElement,
that = this;
if (selector.substr(0, 1) == "#") {
if (parent) {
if (parent.id != selector.substr(1)) {
that.findParents(parent, selector);
} else {
return parent;
}
}
} else if (selector.substr(0, 1) == ".") {
if (parent) {
var classnameArr = parent.className.split(" "),
len = classnameArr.length,
selectt = selector.substr(1),
hasSelector = false;
if (len > 0) {
for (var i = 0; i < len; i++) {
if (classnameArr[i] == selectt) {
hasSelector = true;
break;
}
}
}
if (!hasSelector) {
that.findParents(parent, selector);
} else if (hasSelector) {
return parent;
}
}
}
},
i.prototype.uuid = function() {
var that = this,
randomStr = ['l', 'a', 'y', 'e', 'r', 'n', 'i'],
randomNum = Math.floor(Math.random() * 6);
return function() {
var str = "";
for (var i = 0; i <= randomNum; i++) {
str += randomStr[Math.floor(Math.random() * 6)];
}
return "lyn_" + new Date().getTime() + "_" + (num++) + "_" + (++num) + "_" + str;
} ();
},
i.prototype.click = function(e, o) {
var a = this,
r = a.options;
e.children("a").on("click",
function(e) {
//debugger;
layui.stope(e),
r.click(o)
})
},
i.prototype.spread = function(e, o) {
//debugger;
var a = this,
r = (a.options, e.children(".layui-tree-spread")),
i = e.children("ul"),
n = e.children("a"),
l = function() {
e.data("spread") ? (e.data("spread", null), i.removeClass("layui-show"), r.html(t.arrow[0]),
n.find(".layui-icon").removeClass(branchExtent[1]).addClass(branchExtent[0])) : (e.data("spread", !0), i.addClass("layui-show"), r.html(t.arrow[1]), n.find(".layui-icon").removeClass(branchExtent[0]).addClass(branchExtent[1]))
};
i[0] && (r.on("click", l), n.on("dblclick", l))
},
//n.find(".layui-icon").html(t.branchExtent[0])):(e.data("spread",!0),i.addClass("layui-show"),r.html(t.arrow[1]),
//n.find(".layui-icon").html(t.branchExtent[1]))};i[0]&&(r.on("click",l),n.on("dblclick",l))},
i.prototype.on = function(e) {
var a = this,
i = a.options,
t = "layui-tree-drag";
e.find("i").on("selectstart",
function(e) {
return ! 1
}),
i.drag && o(document).on("mousemove",
function(e) {
var r = a.move;
if (r.from) {
var i = (r.to, o(''));
e.preventDefault(),
o("." + t)[0] || o("body").append(i);
var n = o("." + t)[0] ? o("." + t) : i;
n.addClass("layui-show").html(r.from.elem.children("a").html()),
n.css({
left: e.pageX + 10,
top: e.pageY + 10
})
}
}).on("mouseup",
function(ev) {
var ee = a.move;
if(ee.from && ee.from.elem && ee.from.elem[0]){
//自定义鼠标右击事件
//debugger;
ee.from.elem[0].oncontextmenu = function(){
//debugger;
if(!leftClick){leftClick=true;}
if(typeof i.rightClick=="function" ){
var oEvent=ev.event;
if (!oEvent) oEvent=window.event;
if (oEvent.button==2) {
try { //debugger;
leftClick=!leftClick;
if(!leftClick)
{
layui.stope(e);
i.rightClick(a,ee);
//leftClick=false;
}
} catch(e) {}
oEvent.stopPropagation();
oEvent.preventDefault();
return false;
}
}
}
}
ee.from && (ee.from.elem.children("a").removeClass(r), ee.to && ee.to.elem.children("a").removeClass(r), a.move = {},
o("." + t).remove());
ev.preventDefault();
return false;
})
},
i.prototype.move = {},
i.prototype.drag = function(e, a) {
var i = this,
t = (i.options, e.children("a")),
n = function() {
var t = o(this),
n = i.move;
n.from && (n.to = {
item: a,
elem: e
},
t.addClass(r))
};
t.on("mousedown",
function() {
var o = i.move;
o.from = {
item: a,
elem: e
}
}),
t.on("mouseenter", n).on("mousemove", n).on("mouseleave",
function() {
var e = o(this),
a = i.move;
a.from && (delete a.to, e.removeClass(r))
})
},
e("tree",
function(e) {
var r = new i(e = e || {}),
t = o(e.elem);
return t[0] ? void r.init(t) : a.error("layui.tree 没有找到" + e.elem + "元素");
})
})
三、更多
如果你还需要交流问题,
如果你还有不了解的地方,
如果你需要.NET版本构建tree的后台代码,
如果你需要JAVA版本构建tree的后台代码,
一起学习探讨吧。........
可以加入我们的基地,我们基地的地址是:450342630(QQ群号)