LayUI Tree component extension implementation (search function, check box, custom node icon, right-click menu) (with source code)

Recently, LayUI was selected for the front-end technology selection of the project option. What was not selected was that the function of the tree component was too weak. I didn’t do it. I had to modify the source code myself. The following functions are currently implemented. There is no time to update on github, so stay tuned . Then let's take a look at the extended functions:

1. Extended functions

1. Added the search function of the directory tree

2. Added the realization of checkboxes and event callbacks in the directory tree

3. Added custom settings for root node icon and leaf icon.

4. Added right-click menu and event callback.

Let my mom take a look at the renderings

Search implementation
Search function effect

 

    

Right click menu
Right-click menu implementation

 

Two, let me look at the implementation source code

   Call method

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'), '<span class="search_hint_text">' + value + '</span>'));
								}
							});
							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("<ul class=\"layui-show\"><li><i style=\"paddling-left: 28px;\"></i><input type=\"checkbox\" name=\"ck\" checked=\"checked\" data-parent-id=\"lyn_1554703113157_1_3_lel\" id=\"lyn_1554703113158_3_5_nly\"><a href=\"http://www.layui.com/\" target=\"_blank\"><i class=\"layui-icon Ico_point1\"></i><cite>所有未读</cite></a></li><li><i style=\"paddling-left: 28px;\"></i><input type=\"checkbox\" name=\"ck\" data-parent-id=\"lyn_1554703113157_1_3_lel\" id=\"lyn_1554703113160_5_7_nayryl\"><a href=\"javascript:;\" class=\"\"><i class=\"layui-icon Ico_point2\"></i><cite>置顶邮件</cite></a></li><li><i class=\"layui-icon layui-tree-spread\"></i><input type=\"checkbox\" name=\"ck\" data-parent-id=\"lyn_1554703113157_1_3_lel\" id=\"lyn_1554703113160_7_9_ney\"><a href=\"javascript:;\"><i class=\"layui-icon Ico_fold\"></i><cite>邮件标签邮件</cite></a><ul class=\"\"><li><i style=\"paddling-left: 28px;\"></i><input type=\"checkbox\" name=\"ck\" checked=\"checked\" data-parent-id=\"lyn_1554703113160_7_9_ney\" id=\"lyn_1554703113161_9_11_aa\"><a href=\"http://www.layui.com/\" target=\"_blank\"><i class=\"layui-icon Ico_point1\"></i><cite>所有未读</cite></a></li><li><i style=\"paddling-left: 28px;\"></i><input type=\"checkbox\" name=\"ck\" data-parent-id=\"lyn_1554703113160_7_9_ney\" id=\"lyn_1554703113161_11_13_lrl\"><a href=\"javascript:;\"><i class=\"layui-icon Ico_point2\"></i><cite>置顶邮件</cite></a></li><li><i style=\"paddling-left: 28px;\"></i><input type=\"checkbox\" name=\"ck\" data-parent-id=\"lyn_1554703113160_7_9_ney\" id=\"lyn_1554703113162_13_15_e\"><a href=\"javascript:;\"><i class=\"layui-icon Ico_point3\"></i><cite>邮件标签邮件</cite></a></li></ul></li></ul>");

                             //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 source code

//扩展日志  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: ["&#xe623;", "&#xe625;"],
            checkbox: ["&#xe626;", "&#xe627;"],
            radio: ["&#xe62b;", "&#xe62a;"],
            branch: ["&#xe622;", "&#xe624;"],
            leaf: "&#xe621;"
          },
          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('<ul class="' + (n.spread ? "layui-show": "") + '"></ul>'),
                      s = o(["<li " + (n.spread ? 'data-spread="' + n.spread + '"': "") + ">",
                        function() {
                          return l ? '<i class="layui-icon layui-tree-spread">' + (n.spread ? t.arrow[1] : t.arrow[0]) + '</i>': '<i style="paddling-left: 28px;"></i>';
                        } (),
                        function() {
                          var eleStr = i.check && i.check == "checkbox" ? '<input type="checkbox" name="' + i.checkboxName + '" ' + ((n.checked && n.checked == true) ? 'checked="checked"': "") + (n.checkboxValue ? ('value="' + n.checkboxValue + '"') : "") + 'data-parent-id="' + n.pid + '"' + 'id="' + n.id + '"' + (i.checkboxStyle ? (' style="' + i.checkboxStyle + '"') : "") : '';
                          if (eleStr.length > 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 '<a href="' + (n.href || "javascript:;") + '" ' + (i.target && n.href ? 'target="' + i.target + '"': "") + ">" + ('<i class="layui-icon layui-tree-' + (l ? "branch": "leaf") + '">' + (l ? n.spread ? t.branch[1] : t.branch[0] : t.leaf) + "</i>") + ("<cite>" + (n.name || "未命名") + "</cite></a>")
                          return '<a href="' + (n.href || "javascript:;") + '" '
                              + (i.target && n.href ? 'target="' + i.target + '"': "") + ">"
                              + ('<i class="layui-icon ' + (l ? n.spread ? branchExtent[1] : branchExtent[0] : n.leaf) + '">'
                                  + "</i>") + ("<cite>" + (n.name || "未命名") + "</cite></a>")
                        } (), "</li>"].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('<div class="layui-box ' + t + '"></div>'));
                    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 + "元素");
              })
    })

Three, more

If you still need to communicate questions,

If you still don’t understand,

If you need the .NET version to build the background code of the tree,

If you need the JAVA version to build the background code of the tree,

Let's study and discuss together. ........

You can join our base, the address of our base is: 450342630 (QQ group number)

Guess you like

Origin blog.csdn.net/qq_27532167/article/details/89139039