LayUI Tree 组件扩展实现(搜索功能,复选框,自定义节点图标,右击菜单)(附带源码)

最近项目选项前端技术选型选择了LayUI,没选到的是tree组件的功能实在太弱了,没办了,只能自己修改了源码,目前实现了以下功能,github还没有时间更新敬请期待。那我们来看看扩展功能吧:

一、扩展功能

1,增加了目录树的搜索功能

2,增加了目录树的复选框和事件回调的实现

3,增加了根节点图标和叶子图标自定义设置。

4,增加右键菜单和事件回调。

让我妈看一下效果图吧

LayUI Tree 组件扩展实现(搜索功能,复选框,自定义节点图标,右击菜单)(附带源码)_第1张图片 搜索功能效果

 

    

LayUI Tree 组件扩展实现(搜索功能,复选框,自定义节点图标,右击菜单)(附带源码)_第2张图片 右键菜单实现

 

二、让我看一下实现源码吧

   调用方式

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群号)

    你可能感兴趣的:(js,LayUI)