layui树形组件懒加载实现

         工作中需要用到Layui前端框架,但使用过程中发现需要用到树形组件懒加载方式,可惜的是Layui仍未实现树形组件懒加载,网上大神们写了好多文章介绍但总感觉不如自己写一个。以下代码比较多,可能读者没有耐心看完,我权当是自己作一下笔记吧,以后想起来的时候会持续更新下去,若有什么好的建议,希望能下方给我留言,我一定会想办法改进…
         使用方式也在后方通过实例展示。代码最初不是很多的,只实现了懒加载功能,可后面持续用到懒加载下拉树、懒加载下拉框树形组件、懒加载表格下拉框树形组件,代码便这样慢慢积累起来了。很多方法及实现方式是参考的layui.js,很希望贤心有闲心的时候完善一下layui吧。如果还是不明白,建议直接研读原码,希望能给大家带来帮助。

一、js代码如下:

/**
 
 @Name:layui.treelazy 树,懒加载实现
 @Author:xxx
 @License:MIT

 */

layui.define('form', function(exports) {
	"use strict";

	var $ = layui.$,
		form = layui.form

		//模块名
		,
		MOD_NAME = 'treelazy'

		//外部接口
		,
		treelazy = {
			config: {},
			index: layui[MOD_NAME] ? (layui[MOD_NAME].index + 10000) : 0

				//设置全局项
				,
			set: function(options) {
					var that = this;
					that.config = $.extend({}, that.config, options);
					return that;
				}

				//事件监听
				,
			on: function(events, callback) {
				return layui.onevent.call(this, MOD_NAME, events, callback);
			}
		}

		//操作当前实例
		,
		thisModule = function() {
			var that = this,
				options = that.config,
				id = options.id || that.index;

			thisModule.that[id] = that; //记录当前实例对象
			thisModule.config[id] = options; //记录当前实例配置项

			return {
				config: options
					//重置实例
					,
				reload: function(options) {
					that.reload.call(that, options);
				},
				getChecked: function() {
					return that.getChecked.call(that);
				},
				setChecked: function(id) { //设置值
					return that.setChecked.call(that, id);
				}
			}
		}

		//获取当前实例配置项
		,
		getThisModuleConfig = function(id) {
			var config = thisModule.config[id];
			if (!config) hint.error('The ID option was not found in the ' + MOD_NAME + ' instance');
			return config || null;
		}

		//字符常量
		,
		SHOW = 'layui-show',
		HIDE = 'layui-hide',
		NONE = 'layui-none',
		DISABLED = 'layui-disabled'

		,
		ELEM_VIEW = 'layui-tree',
		ELEM_SET = 'layui-tree-set',
		ICON_CLICK = 'layui-tree-iconClick',
		ICON_ADD = 'layui-icon-addition',
		ICON_SUB = 'layui-icon-subtraction',
		ELEM_ENTRY = 'layui-tree-entry',
		ELEM_MAIN = 'layui-tree-main',
		ELEM_TEXT = 'layui-tree-txt',
		ELEM_PACK = 'layui-tree-pack',
		ELEM_SPREAD = 'layui-tree-spread',
		ELEM_LINE_SHORT = 'layui-tree-setLineShort',
		ELEM_SHOW = 'layui-tree-showLine',
		ELEM_EXTEND = 'layui-tree-lineExtend'

		//构造器
		,
		Class = function(options) {
			var that = this;
			that.index = ++treelazy.index;
			that.config = $.extend({}, that.config, treelazy.config, options);
			that.render();
		};
	treelazy.setTitle = function(elem, title, id) {
		elem.replace('#', '');
		$('#' + elem).find('option').val(id);
		var select = $('#' + elem).next().find('input').val(title);
	};
	treelazy.treeselect = function(param) {
		var elem = param.elem; //id
		var width = param.width ? param.width + 'px' : '100%'; //下拉框文本宽度,默认100%,默认单位px
		var height = param.height ? param.height + 'px' : '200px'; //下拉框高,默认100px
		var placeholder = param.placeholder || '请选择';
		var first = param.first || false; //是否默认选中第一行
		var selectFontColor = param.selectFontColor || '#9F6277'; //默认选中文本颜色,默认#9F6277
		var onlyIconControl = param.onlyIconControl || false; //只能点击图标展开收缩,默认false
		var onlyLeafClick = param.onlyLeafClick || false; //只有点击叶子节点才执行点击方法,默认false
		var treeid = 'tree_' + elem.substring(1);

		//渲染html
		var select = $(elem);
		if (select.next().length > 0) {
			//删除layui渲染的下拉框
			select.next().remove();
		}
		var disabled = select.attr('disabled');
		var disabledClass = disabled ? 'layui-disabled' : '';
		var option = $('<option>');
		var form_select = $('<div class="layui-unselect layui-form-select layui-treeselect" style="width:' + width + ';">');
		var select_title = $('<div class="layui-select-title">');
		var input = $('<input type="text" placeholder="' + placeholder + '" readonly class="layui-input layui-unselect ' +
			disabledClass + '" ' + disabled + '>');
		var edge = $('<i class="layui-edge"></i>');
		var anim = $('<dl class="layui-anim layui-anim-upbit" >');
		var dd = $('<dd>');
		dd.css('height', height);
		var treeDiv = $('<div id="' + treeid + '">');
		//组装入页面
		select_title.append(input);
		select_title.append(edge);
		dd.append(treeDiv);
		anim.append(dd);
		form_select.append(select_title);
		form_select.append(anim);
		select.after(form_select);
		select.append(option);
		//绑定事件
		select_title.on('click', function() {
			var isDisabled = $(this).parent().prev().attr('disabled');
			if (!isDisabled) {
				$(this).next().toggle();
			}
		});
		//初始化渲染树形组件1
		treelazy.render({
			elem: '#' + treeid, //绑定元素
			id: treeid,
			onlyIconControl: onlyIconControl,
			onlyLeafClick: onlyLeafClick,
			selectFontColor: selectFontColor,
			load: function(node, render) {
				param.load(node, function(datas) {
					if (first && node.level == 0) {
						option.val(datas[0].id);
						input.val(datas[0].text);
					}
					render(datas);
				});
			},
			click: function(obj) {
				//返回选中记录
				option.val(obj.data.id);
				input.val(obj.data.text);
				//收回下拉框
				// $(elem).next().removeClass('layui-form-selected');
				$(elem).next().find('.layui-anim').hide();
				//回调点击方法
				param.click ? param.click(obj) : '';
			}
		});
		$(document).on("click", function(e) {
			//点击下拉框外的区域时,关闭下拉框
			var target = $(e.target).parents('.layui-treeselect');
			var targetId = target.prev().attr('id');
			if (target.length == 0 || targetId != elem.substring(1)) {
				// $(elem).next().removeClass('layui-form-selected');
				$(elem).next().find('.layui-anim').hide();
			}
		});
	}
	treelazy.tabletreeselect = function(param) {
		//传入参数
		var _tID = param.tableID;
		var _td = param.td;
		var _colName = param.colName;
		//获取参数
		var $ = layui.$,
			table = layui.table,
			treelazy = layui.treelazy;
		var _rowIndex = _td.parent().data('index'); //获取下标
		var animID = _tID + '_' + _colName + '_anim';
		var cell = _td.find('.layui-table-cell').eq(0);
		//获取单元格内容
		var value = table.cache[_tID][_rowIndex][_colName]; //id:实际值
		var text = cell.text(); //显示值
		//设置单元格获取焦点时的样式
		cell.css({
			'border': '1px solid #008CBA',
			'padding': '0',
			'box-shadow': '1px 1px 20px rgba(0, 10, 10, .15)'
		});
		//构建单元格中下拉框的ID
		var selectId = "select_" + _tID + "_" + _rowIndex;
		//如果没有构建下拉框,则开始构建
		if ($("#" + selectId).length == 0) {
			var closeFlag = true; //标记是否销毁表格下拉框
			var selectDiv = $('<div class="layui-form-select layui-table-select">');
			var input = $('<input type="text" id="' + selectId + '" value="' + text +
				'" readonly="" class="layui-input">');
			input.data('value', value);
			var edge = $('<i class="layui-edge"></i>');
			//下拉图标点击事件
			edge.on('click', function(e) {
				input.trigger('click');
			});
			//下拉框失去焦点事件:判断是否销毁下拉框
			input.on('blur', function(e) {
				if (closeFlag) {
					closeTableselect();
				} else {
					input.focus();
				}
			});
			//下拉框点击事件:切换下拉框显示隐藏
			input.on('click', function(e) {
				if ($("#" + animID).hasClass('layui-hide')) {
					$("#" + animID).removeClass('layui-hide')
				} else {
					$("#" + animID).addClass('layui-hide')
				}
			});
			//将下拉框载入单元格
			selectDiv.append(input).append(edge);
			cell.append(selectDiv);
			input.focus();
			//计算下拉框弹出框的位置及样式
			if ($("#" + animID).length == 0) {
				//自动创建弹出框
				var tree_id = animID + '_tree';
				var $anim = $('<div class="layui-hide layui-table-select-anim" id="' + animID + '">');
				var $anim_select = $('<div class="layui-form-select">');
				var $anim_upbit = $('<dl class="layui-anim layui-anim-upbit" style="display: block;">');
				var $anim_dd = $('<dd style="height: 200px;">');
				var $anim_tree = $('<div id="' + tree_id + '"></div>');
				//载入body
				$anim_dd.append($anim_tree);
				$anim_upbit.append($anim_dd);
				$anim_select.append($anim_upbit);
				$anim.append($anim_select);
				$('body').append($anim);
				//初始化渲染下拉树
				treelazy.render({
					elem: '#' + tree_id, //绑定元素
					id: tree_id,
					showCheckbox: false,
					onlyIconControl: true,
					onlyLeafClick: false,
					load: function(node, render) {
						if (param.load) {
							param.load(node, render);
						} else {

						}
					},
					click: function(obj) {
						$("#" + animID).addClass('layui-hide');
						var id = obj.data.id;
						var text = obj.data.text;
						var tableselect = $(".layui-table-select");
						if (tableselect.length > 0) {
							tableselect.find('input').val(text);
							tableselect.find('input').data("value", id);
						}
						if (param.click) {
							param.click(obj);
						}
					}
				});
			}
			$("#" + animID).find(".layui-form-select").width(cell.width());
			var animTop = cell.offset().top - 1;
			var animLeft = cell.offset().left;
			var winHeight = $(window).height();
			var animHeight = $("#" + animID).find('dd').height();
			if (animTop >= winHeight - animHeight) {
				animTop = animTop - animHeight - cell.height() - 18;
			}
			$("#" + animID).css({
				'position': 'absolute',
				'left': cell.offset().left + 'px',
				'top': animTop + 'px'
			});
			//下拉框弹出框鼠标止悬停时,标记不销毁下拉框
			$("#" + animID).find('dd').on('mouseover', function(e) {
				closeFlag = false;
			}).on('mouseleave', function(e) {
				closeFlag = true;
			});
			//下拉框鼠标止悬停时,标记不销毁下拉框
			input.next().on('mouseover', function(e) {
				closeFlag = false;
			}).on('mouseleave', function(e) {
				closeFlag = true;
			});
			//窗口尺寸变化时,销毁下拉框
			$(window).resize(function() {
				closeTableselect();
			});
			//表格滚动时,销毁下拉框
			cell.parents('.layui-table-main').scroll(function() {
				closeTableselect();
			});
			// 关闭表格中的下拉树形组件方法
			function closeTableselect() {
				cell.css({
					'border': 'none',
					'padding': '0 6px',
					'box-shadow': 'none'
				});
				var value = selectDiv.find('input').data('value');
				var text = selectDiv.find('input').val();
				table.cache[_tID][_rowIndex][_colName] = value;
				cell.text(text);
				selectDiv.remove();
				$("#" + animID).addClass('layui-hide');
			}
		}
	}
	//默认配置
	Class.prototype.config = {
		data: [] //数据

			,
		showCheckbox: false //是否显示复选框
			,
		showLine: true //是否开启连接线
			,
		accordion: false //是否开启手风琴模式
			,
		onlyIconControl: false //是否仅允许节点左侧图标控制展开收缩
			,
		isJump: false //是否允许点击节点时弹出新窗口跳转
			,
		edit: false //是否开启节点的操作图标
			//,showSearch: false  //是否打开节点过滤
			//,drag: false  //是否开启节点拖拽

			,
		text: {
			defaultNodeName: '未命名' //节点默认名称
				,
			none: '无数据' //数据为空时的文本提示
		}
	};

	//重载实例
	Class.prototype.reload = function(options) {
		var that = this;

		layui.each(options, function(key, item) {
			if (item.constructor === Array) delete that.config[key];
		});

		that.config = $.extend(true, {}, that.config, options);
		that.render();
	};

	//主体渲染
	Class.prototype.render = function() {

		var that = this,
			options = that.config,
			datas = options.data;
		var initNode = {
			level: 0
		}
		options.load(initNode, function(datas) {
			that.init(datas, initNode);
		});
		return {
			config: options,
			setChecked: that.setChecked
		};
	};
	Class.prototype.init = function(datas, node) {
		var that = this;
		var ELEM_SET = 'layui-tree-set';
		var ELEM_PACK = 'layui-tree-pack';
		var config = this.config;
		var elem = config.elem; //#tree
		var checkedId = config.checkedId;
		var showCheckbox = config.showCheckbox; //是否显示复选框
		var onlyIconControl = config.onlyIconControl; //是否仅允许节点左侧图标控制展开收缩
		var onlyLeafClick = config.onlyLeafClick || false; //只有点击页子节点才执行点击事件
		var ICONS = config.icons || {
			ICON_ADD: ICON_ADD,
			ICON_SUB: ICON_SUB,
			ICON_FILE: 'layui-icon-file'
		};
		var selectFontColor = config.selectFontColor || '#555'; //选中节点文本颜色
		var root = $(elem);
		var id = that.index;
		var layFilter = 'LAY-tree-' + id;
		this.config.layFilter = layFilter;
		var tree = root.find('.layui-tree');
		var parentNode = tree;
		var setHide = '';
		var checkedClass = '';
		var checked = false;
		//创建根节点
		if (parentNode.length == 0) {
			setHide = 'layui-tree-setHide'; //根节点不显示线
			//创建根节点
			parentNode = $('<div class="layui-tree layui-form layui-tree-line" lay-filter="' + layFilter + '">');
			root.append(parentNode);
		} else if (node.elem) {
			parentNode = node.elem.parents(".layui-tree-entry").eq(0).next('.layui-tree-pack');
			//如果没有 pack,则说明需要渲染
			if (parentNode.length == 0) {
				parentNode = $('<div class="layui-tree-pack" style="display: block;">');
				if (node.elem) {
					checked = node.elem.parents('span').next().next().hasClass('layui-form-checked');
					checkedClass = checked ? 'checked' : '';
				}
			} else {
				//不需要渲染
				return;
			}
			node.elem.parents(".layui-tree-set").eq(0).append(parentNode);
		}
		//创建节点
		$.each(datas, function(index, item) {
			var lineShort = index == datas.length - 1 ? ' layui-tree-setLineShort' : ''; //末节点显示线
			var leaf = item.leaf;
			var dataid = item.id;
			var div_set = $('<div data-id="' + dataid + '" class="layui-tree-set ' + setHide + lineShort + '">');
			var div_entry = $("<div class='layui-tree-entry'></div>");
			var div_main = $("<div class='layui-tree-main'></div>");
			var treeIcon = leaf ? '' : 'layui-tree-icon';
			var icon = leaf ? ICONS.ICON_FILE : ICONS.ICON_ADD;
			var span = $("<span class='layui-tree-iconClick " + treeIcon + "'></span>");
			var i = $("<i class='layui-icon " + icon + "'></i>");
			if (!leaf) {
				i.bind('click', function() {
					addition_click();
				});

				function addition_click() {
					var level = i.parents(".layui-tree-set").length;
					var loadNode = {
						level: level,
						data: item
					}
					config.load(loadNode, function(datas) {
						var spread = i.hasClass(ICONS.ICON_ADD);
						if (spread) { //展开
							i.addClass(ICONS.ICON_SUB).removeClass(ICONS.ICON_ADD);
							i.parents('.layui-tree-entry').next(".layui-tree-pack").slideDown(200);
						} else {
							i.addClass(ICONS.ICON_ADD).removeClass(ICONS.ICON_SUB);
							i.parents('.layui-tree-entry').next(".layui-tree-pack").slideUp(200);
						}
						loadNode.elem = i;
						that.init(datas, loadNode);
					});
				}
			}

			var text = $("<span class='layui-tree-txt'>" + item.text + "</span>");
			text.bind('click', function() {
				if (!onlyIconControl) {
					i.trigger('click');
				}
				if ((onlyLeafClick && leaf) || !onlyLeafClick) {
					root.find('.text_click').removeClass('text_click').css('color', '#555');
					text.addClass('text_click');
					root.find('.text_click').css('color', selectFontColor);
					config.click ? config.click({
						data: item,
						pid: 0
					}) : '';
				}
			});

			span.append(i);
			div_main.append(span);
			if (showCheckbox) {
				if (checkedId) {
					//如果动态设置了选中,则判断新节点是否在其中
					if ($.inArray(parseInt(dataid), checkedId) == -1) {
						checkedClass = '';
					} else {
						checkedClass = 'checked';
					}
				}
				var checkbox = $("<input type='checkbox' name='layuiTreeCheck' lay-skin='primary' value='" + dataid + "' " +
					checkedClass +
					">");
				div_main.append(checkbox);
			}
			div_main.append(text);
			div_entry.append(div_main);
			div_set.append(div_entry);
			parentNode.append(div_set);
		});
		if (showCheckbox) {
			that.renderCheckbox();
		}

	}
	//渲染复选框
	Class.prototype.renderCheckbox = function(options) {
		var that = this;
		var root = $(that.config.elem);
		form.render('checkbox', that.config.layFilter);
		var checkbox = root.find('input[name="layuiTreeCheck"]');
		var checkedids = [];
		checkbox.each(function() {
			let checked = $(this)[0].checked;
			if (checked) {
				checkedids.push($(this)[0].value);
			}
		});
		//给复选框绑定事件
		root.find('.layui-form-checkbox').bind('click', function() {
			//消除动态选择的数组
			delete that.config.checkedId;
			var elemCheckbox = $(this).prev('input[name="layuiTreeCheck"]');
			var checked = elemCheckbox.prop('checked');
			//同步子节点选中状态
			var childs = elemCheckbox.parents('.layui-tree-entry').eq(0).next().find('input[name="layuiTreeCheck"]');
			childs.each(function() {
				this.checked = checked;
			});
			//同步父选中状态
			var setParentsChecked = function(thisNodeElem) {
				//若无父节点,则终止递归
				if (!thisNodeElem.parents('.' + ELEM_SET)[0]) return;
				var state, parentPack = thisNodeElem.parent('.' + ELEM_PACK),
					parentNodeElem = parentPack.parent(),
					parentCheckbox = parentPack.prev().find('input[name="layuiTreeCheck"]');
				//如果子节点有任意一条选中,则父节点为选中状态
				if (checked) {
					parentCheckbox.prop('checked', checked);
				} else { //如果当前节点取消选中,则根据计算“兄弟和子孙”节点选中状态,来同步父节点选中状态
					parentPack.find('input[name="layuiTreeCheck"]').each(function() {
						if (this.checked) {
							state = true;
						}
					});

					//如果兄弟子孙节点全部未选中,则父节点也应为非选中状态
					state || parentCheckbox.prop('checked', false);
				}
				//向父节点递归
				setParentsChecked(parentNodeElem);
			}
			setParentsChecked(elemCheckbox.parents('.' + ELEM_SET).eq(0));
			that.renderCheckbox();
		});
	}

	function renderCheckbox() {
		form.render('checkbox', that.config.layFilter);
		//给复选框绑定事件
		root.find('.layui-form-checkbox').bind('click', function() {
			var elemCheckbox = $(this).prev('input[name="layuiTreeCheck"]');
			var checked = elemCheckbox.prop('checked');
			//同步子节点选中状态
			var childs = elemCheckbox.parents('.layui-tree-entry').eq(0).next().find('input[name="layuiTreeCheck"]');
			childs.each(function() {
				this.checked = checked;
			});
			//同步父选中状态
			var setParentsChecked = function(thisNodeElem) {
				//若无父节点,则终止递归
				if (!thisNodeElem.parents('.' + ELEM_SET)[0]) return;
				var state, parentPack = thisNodeElem.parent('.' + ELEM_PACK),
					parentNodeElem = parentPack.parent(),
					parentCheckbox = parentPack.prev().find('input[name="layuiTreeCheck"]');
				//如果子节点有任意一条选中,则父节点为选中状态
				if (checked) {
					parentCheckbox.prop('checked', checked);
				} else { //如果当前节点取消选中,则根据计算“兄弟和子孙”节点选中状态,来同步父节点选中状态
					parentPack.find('input[name="layuiTreeCheck"]').each(function() {
						if (this.checked) {
							state = true;
						}
					});

					//如果兄弟子孙节点全部未选中,则父节点也应为非选中状态
					state || parentCheckbox.prop('checked', false);
				}
				//向父节点递归
				setParentsChecked(parentNodeElem);
			}
			setParentsChecked(elemCheckbox.parents('.' + ELEM_SET).eq(0));
			renderCheckbox();
			//调用事件
			that.config.checkboxClick ? that.config.checkboxClick() : '';
		});
	}
	//渲染表单
	Class.prototype.renderForm = function(type) {
		form.render(type, 'LAY-tree-' + this.index);
	};
	//节点解析
	Class.prototype.treelazy = function(elem, children) {
		var that = this,
			options = that.config,
			data = children || options.data;

		//遍历数据
		layui.each(data, function(index, item) {
			var hasChild = item.children && item.children.length > 0,
				packDiv = $('<div class="layui-tree-pack" ' + (item.spread ? 'style="display: block;"' : '') + '"></div>'),
				entryDiv = $(['<div data-id="' + item.id + '" class="layui-tree-set' + (item.spread ? " layui-tree-spread" :
						"") + (item.checked ? " layui-tree-checkedFirst" : "") + '">', '<div ' + (options.drag && !item.fixed ?
						'draggable="true"' : '') + ' class="layui-tree-entry">', '<div class="layui-tree-main">'
					//箭头
					,
					function() {
						if (options.showLine) {
							if (hasChild) {
								return '<span class="layui-tree-iconClick layui-tree-icon"><i class="layui-icon ' + (item.spread ?
									"layui-icon-subtraction" : "layui-icon-addition") + '"></i></span>';
							} else {
								return '<span class="layui-tree-iconClick"><i class="layui-icon layui-icon-file"></i></span>';
							};
						} else {
							return '<span class="layui-tree-iconClick"><i class="layui-tree-iconArrow ' + (hasChild ? "" : HIDE) +
								'"></i></span>';
						};
					}()

					//复选框
					,
					function() {
						return options.showCheckbox ? '<input type="checkbox" name="layuiTreeCheck" lay-skin="primary" ' + (item.disabled ?
							"disabled" : "") + '  value="' + item.id + '">' : '';
					}()

					//节点
					,
					function() {
						if (options.isJump && item.href) {
							return '<a href="' + item.href + '" target="_blank" class="' + ELEM_TEXT + '">' + (item.title || item.label ||
								options.text.defaultNodeName) + '</a>';
						} else {
							return '<span class="' + ELEM_TEXT + (item.disabled ? ' ' + DISABLED : '') + '">' + (item.title || item.label ||
								options.text.defaultNodeName) + '</span>';
						}
					}(), '</div>'

					//节点操作图标
					,
					function() {
						if (!options.edit) return '';

						var editIcon = {
								add: '<i class="layui-icon layui-icon-add-1"  data-type="add"></i>',
								update: '<i class="layui-icon layui-icon-edit" data-type="update"></i>',
								del: '<i class="layui-icon layui-icon-delete" data-type="del"></i>'
							},
							arr = ['<div class="layui-btn-group layui-tree-btnGroup">'];

						if (options.edit === true) {
							options.edit = ['update', 'del']
						}

						if (typeof options.edit === 'object') {
							layui.each(options.edit, function(i, val) {
								arr.push(editIcon[val] || '')
							});
							return arr.join('') + '</div>';
						}
					}(), '</div></div>'
				].join(''));

			//如果有子节点,则递归继续生成树
			if (hasChild) {
				entryDiv.append(packDiv);
				that.treelazy(packDiv, item.children);
			};

			elem.append(entryDiv);

			//若有前置节点,前置节点加连接线
			if (entryDiv.prev('.' + ELEM_SET)[0]) {
				entryDiv.prev().children('.layui-tree-pack').addClass('layui-tree-showLine');
			};

			//若无子节点,则父节点加延伸线
			if (!hasChild) {
				entryDiv.parent('.layui-tree-pack').addClass('layui-tree-lineExtend');
			};

			//展开节点操作
			that.spread(entryDiv, item);

			//选择框
			if (options.showCheckbox) {
				that.checkClick(entryDiv, item);
			}

			//操作节点
			options.edit && that.operate(entryDiv, item);

		});
	};

	//展开节点
	Class.prototype.spread = function(elem, item) {
		var that = this,
			options = that.config,
			entry = elem.children('.' + ELEM_ENTRY),
			elemMain = entry.children('.' + ELEM_MAIN),
			elemIcon = entry.find('.' + ICON_CLICK),
			elemText = entry.find('.' + ELEM_TEXT),
			touchOpen = options.onlyIconControl ? elemIcon : elemMain //判断展开通过节点还是箭头图标
			,
			state = '';

		//展开收缩
		touchOpen.on('click', function(e) {
			var packCont = elem.children('.' + ELEM_PACK),
				iconClick = touchOpen.children('.layui-icon')[0] ? touchOpen.children('.layui-icon') : touchOpen.find(
					'.layui-tree-icon').children('.layui-icon');

			//若没有子节点
			if (!packCont[0]) {
				state = 'normal';
			} else {
				if (elem.hasClass(ELEM_SPREAD)) {
					elem.removeClass(ELEM_SPREAD);
					packCont.slideUp(200);
					iconClick.removeClass(ICON_SUB).addClass(ICON_ADD);
				} else {
					elem.addClass(ELEM_SPREAD);
					packCont.slideDown(200);
					iconClick.addClass(ICON_SUB).removeClass(ICON_ADD);

					//是否手风琴
					if (options.accordion) {
						var sibls = elem.siblings('.' + ELEM_SET);
						sibls.removeClass(ELEM_SPREAD);
						sibls.children('.' + ELEM_PACK).slideUp(200);
						sibls.find('.layui-tree-icon').children('.layui-icon').removeClass(ICON_SUB).addClass(ICON_ADD);
					};
				};
			};
		});

		//点击回调
		elemText.on('click', function() {
			var othis = $(this);

			//判断是否禁用状态
			if (othis.hasClass(DISABLED)) return;

			//判断展开收缩状态
			if (elem.hasClass(ELEM_SPREAD)) {
				state = options.onlyIconControl ? 'open' : 'close';
			} else {
				state = options.onlyIconControl ? 'close' : 'open';
			}

			//点击产生的回调
			options.click && options.click({
				elem: elem,
				state: state,
				data: item
			});
		});
	};

	//计算复选框选中状态
	Class.prototype.setCheckbox = function(elem, item, elemCheckbox) {
		var that = this,
			options = that.config,
			checked = elemCheckbox.prop('checked');

		//同步子节点选中状态
		if (typeof item.children === 'object' || elem.find('.' + ELEM_PACK)[0]) {
			var childs = elem.find('.' + ELEM_PACK).find('input[name="layuiTreeCheck"]');
			childs.each(function() {
				if (this.disabled) return; //不可点击则跳过
				this.checked = checked;
			});
		};

		//同步父选中状态
		var setParentsChecked = function(thisNodeElem) {
			//若无父节点,则终止递归
			if (!thisNodeElem.parents('.' + ELEM_SET)[0]) return;

			var state, parentPack = thisNodeElem.parent('.' + ELEM_PACK),
				parentNodeElem = parentPack.parent(),
				parentCheckbox = parentPack.prev().find('input[name="layuiTreeCheck"]');


			//如果子节点有任意一条选中,则父节点为选中状态
			if (checked) {
				parentCheckbox.prop('checked', checked);
			} else { //如果当前节点取消选中,则根据计算“兄弟和子孙”节点选中状态,来同步父节点选中状态
				parentPack.find('input[name="layuiTreeCheck"]').each(function() {
					if (this.checked) {
						state = true;
					}
				});

				//如果兄弟子孙节点全部未选中,则父节点也应为非选中状态
				state || parentCheckbox.prop('checked', false);
			}

			//向父节点递归
			setParentsChecked(parentNodeElem);
		};

		setParentsChecked(elem);

		that.renderForm('checkbox');
	};

	//复选框选择
	Class.prototype.checkClick = function(elem, item) {
		var that = this,
			options = that.config,
			entry = elem.children('.' + ELEM_ENTRY),
			elemMain = entry.children('.' + ELEM_MAIN);

		elemMain.on('click', 'input[name="layuiTreeCheck"]+', function(e) {
			layui.stope(e); //阻止点击节点事件

			var elemCheckbox = $(this).prev(),
				checked = elemCheckbox.prop('checked');

			if (elemCheckbox.prop('disabled')) return;

			that.setCheckbox(elem, item, elemCheckbox);

			//复选框点击产生的回调
			options.oncheck && options.oncheck({
				elem: elem,
				checked: checked,
				data: item
			});
		});
	};

	//节点操作
	Class.prototype.operate = function(elem, item) {
		var that = this,
			options = that.config,
			entry = elem.children('.' + ELEM_ENTRY),
			elemMain = entry.children('.' + ELEM_MAIN);

		entry.children('.layui-tree-btnGroup').on('click', '.layui-icon', function(e) {
			layui.stope(e); //阻止节点操作

			var type = $(this).data("type"),
				packCont = elem.children('.' + ELEM_PACK),
				returnObj = {
					data: item,
					type: type,
					elem: elem
				};
			//增加
			if (type == 'add') {
				//若节点本身无子节点
				if (!packCont[0]) {
					//若开启连接线,更改图标样式
					if (options.showLine) {
						elemMain.find('.' + ICON_CLICK).addClass('layui-tree-icon');
						elemMain.find('.' + ICON_CLICK).children('.layui-icon').addClass(ICON_ADD).removeClass('layui-icon-file');
						//若未开启连接线,显示箭头
					} else {
						elemMain.find('.layui-tree-iconArrow').removeClass(HIDE);
					};
					//节点添加子节点容器
					elem.append('<div class="layui-tree-pack"></div>');
				};

				//新增节点
				var key = options.operate && options.operate(returnObj),
					obj = {};
				obj.title = options.text.defaultNodeName;
				obj.id = key;
				that.treelazy(elem.children('.' + ELEM_PACK), [obj]);

				//放在新增后面,因为要对元素进行操作
				if (options.showLine) {
					//节点本身无子节点
					if (!packCont[0]) {
						//遍历兄弟节点,判断兄弟节点是否有子节点
						var siblings = elem.siblings('.' + ELEM_SET),
							num = 1,
							parentPack = elem.parent('.' + ELEM_PACK);
						layui.each(siblings, function(index, i) {
							if (!$(i).children('.' + ELEM_PACK)[0]) {
								num = 0;
							};
						});

						//若兄弟节点都有子节点
						if (num == 1) {
							//兄弟节点添加连接线
							siblings.children('.' + ELEM_PACK).addClass(ELEM_SHOW);
							siblings.children('.' + ELEM_PACK).children('.' + ELEM_SET).removeClass(ELEM_LINE_SHORT);
							elem.children('.' + ELEM_PACK).addClass(ELEM_SHOW);
							//父级移除延伸线
							parentPack.removeClass(ELEM_EXTEND);
							//同层节点最后一个更改线的状态
							parentPack.children('.' + ELEM_SET).last().children('.' + ELEM_PACK).children('.' + ELEM_SET).last().addClass(
								ELEM_LINE_SHORT);
						} else {
							elem.children('.' + ELEM_PACK).children('.' + ELEM_SET).addClass(ELEM_LINE_SHORT);
						};
					} else {
						//添加延伸线
						if (!packCont.hasClass(ELEM_EXTEND)) {
							packCont.addClass(ELEM_EXTEND);
						};
						//子节点添加延伸线
						elem.find('.' + ELEM_PACK).each(function() {
							$(this).children('.' + ELEM_SET).last().addClass(ELEM_LINE_SHORT);
						});
						//如果前一个节点有延伸线
						if (packCont.children('.' + ELEM_SET).last().prev().hasClass(ELEM_LINE_SHORT)) {
							packCont.children('.' + ELEM_SET).last().prev().removeClass(ELEM_LINE_SHORT);
						} else {
							//若之前的没有,说明处于连接状态
							packCont.children('.' + ELEM_SET).last().removeClass(ELEM_LINE_SHORT);
						};
						//若是最外层,要始终保持相连的状态
						if (!elem.parent('.' + ELEM_PACK)[0] && elem.next()[0]) {
							packCont.children('.' + ELEM_SET).last().removeClass(ELEM_LINE_SHORT);
						};
					};
				};
				if (!options.showCheckbox) return;
				//若开启复选框,同步新增节点状态
				if (elemMain.find('input[name="layuiTreeCheck"]')[0].checked) {
					var packLast = elem.children('.' + ELEM_PACK).children('.' + ELEM_SET).last();
					packLast.find('input[name="layuiTreeCheck"]')[0].checked = true;
				};
				that.renderForm('checkbox');

				//修改
			} else if (type == 'update') {
				var text = elemMain.children('.' + ELEM_TEXT).html();
				elemMain.children('.' + ELEM_TEXT).html('');
				//添加输入框,覆盖在文字上方
				elemMain.append('<input type="text" class="layui-tree-editInput">');
				//获取焦点
				elemMain.children('.layui-tree-editInput').val(text).focus();
				//嵌入文字移除输入框
				var getVal = function(input) {
					var textNew = input.val().trim();
					textNew = textNew ? textNew : options.text.defaultNodeName;
					input.remove();
					elemMain.children('.' + ELEM_TEXT).html(textNew);

					//同步数据
					returnObj.data.title = textNew;

					//节点修改的回调
					options.operate && options.operate(returnObj);
				};
				//失去焦点
				elemMain.children('.layui-tree-editInput').blur(function() {
					getVal($(this));
				});
				//回车
				elemMain.children('.layui-tree-editInput').on('keydown', function(e) {
					if (e.keyCode === 13) {
						e.preventDefault();
						getVal($(this));
					};
				});

				//删除
			} else {
				options.operate && options.operate(returnObj); //节点删除的回调
				returnObj.status = 'remove'; //标注节点删除

				//若删除最后一个,显示空数据提示
				if (!elem.prev('.' + ELEM_SET)[0] && !elem.next('.' + ELEM_SET)[0] && !elem.parent('.' + ELEM_PACK)[0]) {
					elem.remove();
					that.elem.append(that.elemNone);
					return;
				};
				//若有兄弟节点
				if (elem.siblings('.' + ELEM_SET).children('.' + ELEM_ENTRY)[0]) {
					//若开启复选框
					if (options.showCheckbox) {
						//若开启复选框,进行下步操作
						var elemDel = function(elem) {
							//若无父结点,则不执行
							if (!elem.parents('.' + ELEM_SET)[0]) return;
							var siblingTree = elem.siblings('.' + ELEM_SET).children('.' + ELEM_ENTRY),
								parentTree = elem.parent('.' + ELEM_PACK).prev(),
								checkState = parentTree.find('input[name="layuiTreeCheck"]')[0],
								state = 1,
								num = 0;
							//若父节点未勾选
							if (checkState.checked == false) {
								//遍历兄弟节点
								siblingTree.each(function(i, item1) {
									var input = $(item1).find('input[name="layuiTreeCheck"]')[0]
									if (input.checked == false && !input.disabled) {
										state = 0;
									};
									//判断是否全为不可勾选框
									if (!input.disabled) {
										num = 1;
									};
								});
								//若有可勾选选择框并且已勾选
								if (state == 1 && num == 1) {
									//勾选父节点
									checkState.checked = true;
									that.renderForm('checkbox');
									//向上遍历祖先节点
									elemDel(parentTree.parent('.' + ELEM_SET));
								};
							};
						};
						elemDel(elem);
					};
					//若开启连接线
					if (options.showLine) {
						//遍历兄弟节点,判断兄弟节点是否有子节点
						var siblings = elem.siblings('.' + ELEM_SET),
							num = 1,
							parentPack = elem.parent('.' + ELEM_PACK);
						layui.each(siblings, function(index, i) {
							if (!$(i).children('.' + ELEM_PACK)[0]) {
								num = 0;
							};
						});
						//若兄弟节点都有子节点
						if (num == 1) {
							//若节点本身无子节点
							if (!packCont[0]) {
								//父级去除延伸线,因为此时子节点里没有空节点
								parentPack.removeClass(ELEM_EXTEND);
								siblings.children('.' + ELEM_PACK).addClass(ELEM_SHOW);
								siblings.children('.' + ELEM_PACK).children('.' + ELEM_SET).removeClass(ELEM_LINE_SHORT);
							};
							//若为最后一个节点
							if (!elem.next()[0]) {
								elem.prev().children('.' + ELEM_PACK).children('.' + ELEM_SET).last().addClass(ELEM_LINE_SHORT);
							} else {
								parentPack.children('.' + ELEM_SET).last().children('.' + ELEM_PACK).children('.' + ELEM_SET).last().addClass(
									ELEM_LINE_SHORT);
							};
							//若为最外层最后一个节点,去除前一个结点的连接线
							if (!elem.next()[0] && !elem.parents('.' + ELEM_SET)[1] && !elem.parents('.' + ELEM_SET).eq(0).next()[0]) {
								elem.prev('.' + ELEM_SET).addClass(ELEM_LINE_SHORT);
							};
						} else {
							//若为最后一个节点且有延伸线
							if (!elem.next()[0] && elem.hasClass(ELEM_LINE_SHORT)) {
								elem.prev().addClass(ELEM_LINE_SHORT);
							};
						};
					};

				} else {
					//若无兄弟节点
					var prevDiv = elem.parent('.' + ELEM_PACK).prev();
					//若开启了连接线
					if (options.showLine) {
						prevDiv.find('.' + ICON_CLICK).removeClass('layui-tree-icon');
						prevDiv.find('.' + ICON_CLICK).children('.layui-icon').removeClass(ICON_SUB).addClass('layui-icon-file');
						//父节点所在层添加延伸线
						var pare = prevDiv.parents('.' + ELEM_PACK).eq(0);
						pare.addClass(ELEM_EXTEND);

						//兄弟节点最后子节点添加延伸线
						pare.children('.' + ELEM_SET).each(function() {
							$(this).children('.' + ELEM_PACK).children('.' + ELEM_SET).last().addClass(ELEM_LINE_SHORT);
						});
					} else {
						//父节点隐藏箭头
						prevDiv.find('.layui-tree-iconArrow').addClass(HIDE);
					};
					//移除展开属性
					elem.parents('.' + ELEM_SET).eq(0).removeClass(ELEM_SPREAD);
					//移除节点容器
					elem.parent('.' + ELEM_PACK).remove();
				};

				elem.remove();


			};
		});
	};

	//拖拽
	Class.prototype.drag = function() {
		var that = this,
			options = that.config;

		that.elem.on('dragstart', '.' + ELEM_ENTRY, function() {
			var parent = $(this).parent('.' + ELEM_SET),
				pares = parent.parents('.' + ELEM_SET)[0] ? parent.parents('.' + ELEM_SET).eq(0) : '未找到父节点';

			//开始拖拽触发的回调
			options.dragstart && options.dragstart(parent, pares);
		});

		that.elem.on('dragend', '.' + ELEM_ENTRY, function(e) {
			var e = e || event,
				disY = e.clientY,
				olds = $(this),
				setParent = olds.parent('.' + ELEM_SET),
				setHeight = setParent.height(),
				setTop = setParent.offset().top,
				elemSet = that.elem.find('.' + ELEM_SET),
				elemHeight = that.elem.height(),
				elemTop = that.elem.offset().top,
				maxTop = elemHeight + elemTop - 13;
			//原父节点
			var isTree = setParent.parents('.' + ELEM_SET)[0],
				nextOld = setParent.next()[0];
			if (isTree) {
				var parentPack = setParent.parent('.' + ELEM_PACK),
					parentSet = setParent.parents('.' + ELEM_SET).eq(0),
					warpPack = parentSet.parent('.' + ELEM_PACK),
					parentTop = parentSet.offset().top,
					siblingOld = setParent.siblings(),
					num = parentSet.children('.' + ELEM_PACK).children('.' + ELEM_SET).length;
			};
			//原节点操作
			var setDel = function(parentSet) {
				//若为最后一个节点操作
				if (!isTree && !nextOld) {
					that.elem.children('.' + ELEM_SET).last().children('.' + ELEM_PACK).children('.' + ELEM_SET).last().addClass(
						ELEM_LINE_SHORT);
				};
				//若为最外层节点,不做下列操作
				if (!isTree) {
					setParent.removeClass('layui-tree-setHide');
					return;
				};

				//若为唯一子节点
				if (num == 1) {
					if (options.showLine) {
						parentSet.find('.' + ICON_CLICK).removeClass('layui-tree-icon');
						parentSet.find('.' + ICON_CLICK).children('.layui-icon').removeClass(ICON_SUB).addClass('layui-icon-file');
						warpPack.addClass(ELEM_EXTEND);
						warpPack.children('.' + ELEM_SET).children('.' + ELEM_PACK).each(function() {
							$(this).children('.' + ELEM_SET).last().addClass(ELEM_LINE_SHORT);
						});
					} else {
						parentSet.find('.layui-tree-iconArrow').addClass(HIDE);
					};
					parentSet.children('.' + ELEM_PACK).remove();
					parentSet.removeClass(ELEM_SPREAD);
				} else {
					//若开启连接线
					if (options.showLine) {
						//遍历兄弟节点,判断兄弟节点是否有子节点
						var number = 1;
						layui.each(siblingOld, function(index, i) {
							if (!$(i).children('.' + ELEM_PACK)[0]) {
								number = 0;
							};
						});

						//若兄弟节点都有子节点
						if (number == 1) {
							//若节点本身无子节点
							if (!setParent.children('.' + ELEM_PACK)[0]) {
								//父级去除延伸线,因为此时子节点里没有空节点
								parentPack.removeClass(ELEM_EXTEND);
								siblingOld.children('.' + ELEM_PACK).addClass(ELEM_SHOW);
								siblingOld.children('.' + ELEM_PACK).children('.' + ELEM_SET).removeClass(ELEM_LINE_SHORT);
							};
							//若为最后一个节点
							parentPack.children('.' + ELEM_SET).last().children('.' + ELEM_PACK).children('.' + ELEM_SET).last().addClass(
								ELEM_LINE_SHORT);
							//若为最外层最后一个节点,去除前一个结点的连接线
							if (!nextOld && !parentSet.parents('.' + ELEM_SET)[0] && !parentSet.next()[0]) {
								parentPack.children('.' + ELEM_SET).last().addClass(ELEM_LINE_SHORT);
							};
						} else {
							//若为最后一个节点且有延伸线
							if (!nextOld && setParent.hasClass(ELEM_LINE_SHORT)) {
								parentPack.children('.' + ELEM_SET).last().addClass(ELEM_LINE_SHORT);
							};
						};
					};
					//若开启复选框
					if (options.showCheckbox) {
						//若开启复选框,进行下步操作
						var elemRemove = function(elem) {
							//若无父结点,则不执行
							if (elem) {
								if (!elem.parents('.' + ELEM_SET)[0]) return;
							} else {
								if (!parentSet[0]) return;
							};
							var siblingTree = elem ? elem.siblings().children('.' + ELEM_ENTRY) : siblingOld.children('.' +
									ELEM_ENTRY),
								parentTree = elem ? elem.parent('.' + ELEM_PACK).prev() : parentPack.prev(),
								checkState = parentTree.find('input[name="layuiTreeCheck"]')[0],
								state = 1,
								ndig = 0;
							//若父节点未勾选
							if (checkState.checked == false) {
								//遍历兄弟节点
								siblingTree.each(function(i, item1) {
									var input = $(item1).find('input[name="layuiTreeCheck"]')[0];
									if (input.checked == false && !input.disabled) {
										state = 0
									};
									//判断是否全为不可勾选框
									if (!input.disabled) {
										ndig = 1
									};
								});
								//若有可勾选选择框并且已勾选
								if (state == 1 && ndig == 1) {
									//勾选父节点
									checkState.checked = true;
									that.renderForm('checkbox');
									//向上遍历祖先节点
									elemRemove(parentTree.parent('.' + ELEM_SET) || parentSet);
								};
							};
						};
						elemRemove();
					};
				};
			};

			//查找
			elemSet.each(function() {
				//筛选可插入位置
				if ($(this).height() != 0) {
					//若在本身位置
					if ((disY > setTop && disY < setTop + setHeight)) {
						options.dragend && options.dragend('drag error');
						return;
					};
					//若仅有一个子元素
					if (num == 1 && disY > parentTop && disY < setTop + setHeight) {
						options.dragend && options.dragend('drag error');
						return;
					};
					var thisTop = $(this).offset().top;

					//若位于元素上
					if ((disY > thisTop) && (disY < thisTop + 15)) {
						//若元素无子节点
						if (!$(this).children('.' + ELEM_PACK)[0]) {
							if (options.showLine) {
								$(this).find('.' + ICON_CLICK).eq(0).addClass('layui-tree-icon');
								$(this).find('.' + ICON_CLICK).eq(0).children('.layui-icon').addClass(ICON_ADD).removeClass(
									'layui-icon-file');
							} else {
								$(this).find(".layui-tree-iconArrow").removeClass(HIDE);
							};
							$(this).append('<div class="layui-tree-pack"></div>');
						};
						//插入元素
						$(this).children('.' + ELEM_PACK).append(setParent);
						setDel(parentSet);
						//若开启连接线,更改线状态
						if (options.showLine) {
							var children = $(this).children('.' + ELEM_PACK).children('.' + ELEM_SET);
							setParent.children('.' + ELEM_PACK).children('.' + ELEM_SET).last().addClass(ELEM_LINE_SHORT);
							if (children.length == 1) {
								//遍历兄弟节点,判断兄弟节点是否有子节点
								var siblings = $(this).siblings('.' + ELEM_SET),
									ss = 1,
									parentPack = $(this).parent('.' + ELEM_PACK);
								layui.each(siblings, function(index, i) {
									if (!$(i).children('.' + ELEM_PACK)[0]) {
										ss = 0;
									};
								});
								//若兄弟节点都有子节点
								if (ss == 1) {
									//兄弟节点添加连接线
									siblings.children('.' + ELEM_PACK).addClass(ELEM_SHOW);
									siblings.children('.' + ELEM_PACK).children('.' + ELEM_SET).removeClass(ELEM_LINE_SHORT);
									$(this).children('.' + ELEM_PACK).addClass(ELEM_SHOW);
									//父级移除延伸线
									parentPack.removeClass(ELEM_EXTEND);
									//同层节点最后一个去除连接线
									parentPack.children('.' + ELEM_SET).last().children('.' + ELEM_PACK).children('.' + ELEM_SET).last().addClass(
										ELEM_LINE_SHORT).removeClass('layui-tree-setHide');
								} else {
									$(this).children('.' + ELEM_PACK).children('.' + ELEM_SET).addClass(ELEM_LINE_SHORT).removeClass(
										'layui-tree-setHide');
								};
							} else {
								//若原子节点含有延伸线
								if (setParent.prev('.' + ELEM_SET).hasClass(ELEM_LINE_SHORT)) {
									setParent.prev('.' + ELEM_SET).removeClass(ELEM_LINE_SHORT);
									setParent.addClass(ELEM_LINE_SHORT);
								} else {
									//清除之前状态
									setParent.removeClass('layui-tree-setLineShort layui-tree-setHide');
									//若添加节点无子节点
									if (!setParent.children('.' + ELEM_PACK)[0]) {
										//兄弟节点子节点添加延伸线
										setParent.siblings('.' + ELEM_SET).find('.' + ELEM_PACK).each(function() {
											$(this).children('.' + ELEM_SET).last().addClass(ELEM_LINE_SHORT);
										});
									} else {
										setParent.prev('.' + ELEM_SET).children('.' + ELEM_PACK).children('.' + ELEM_SET).last().removeClass(
											ELEM_LINE_SHORT);
									};
								};
								//若无下兄弟节点
								if (!$(this).next()[0]) {
									setParent.addClass(ELEM_LINE_SHORT);
								};
							};
						};
						//若开启复选框,同步新增节点状态
						if (options.showCheckbox) {
							if ($(this).children('.' + ELEM_ENTRY).find('input[name="layuiTreeCheck"]')[0].checked) {
								var packLast = setParent.children('.' + ELEM_ENTRY);
								packLast.find('input[name="layuiTreeCheck"]+').click();
							};
						};
						options.dragend && options.dragend('drag success', setParent, $(this));
						return false;

						//若位于元素上方
					} else if (disY < thisTop) {
						$(this).before(setParent);
						setDel(parentSet);
						//若开启连接线,更改线状态
						if (options.showLine) {
							var packCont = setParent.children('.' + ELEM_PACK),
								setFirst = $(this).parents('.' + ELEM_SET).eq(0),
								setPackLast = setFirst.children('.' + ELEM_PACK).children('.' + ELEM_SET).last();
							if (packCont[0]) {
								setParent.removeClass(ELEM_LINE_SHORT);
								packCont.children('.' + ELEM_SET).last().removeClass(ELEM_LINE_SHORT);
								//遍历兄弟节点,判断兄弟节点是否有子节点
								var siblings = setParent.siblings('.' + ELEM_SET),
									ss = 1;
								layui.each(siblings, function(index, i) {
									if (!$(i).children('.' + ELEM_PACK)[0]) {
										ss = 0;
									};
								});
								//若兄弟节点都有子节点
								if (ss == 1) {
									if (setFirst[0]) {
										//兄弟节点添加连接线
										siblings.children('.' + ELEM_PACK).addClass(ELEM_SHOW);
										siblings.children('.' + ELEM_PACK).children('.' + ELEM_SET).removeClass(ELEM_LINE_SHORT);
										//同层节点最后一个添加延伸线
										setPackLast.children('.' + ELEM_PACK).children('.' + ELEM_SET).last().addClass(ELEM_LINE_SHORT).removeClass(
											ELEM_SHOW);
									};
								} else {
									setParent.children('.' + ELEM_PACK).children('.' + ELEM_SET).last().addClass(ELEM_LINE_SHORT);
								};

								//若是最外层,要始终保持相连的状态
								if (!setFirst.parent('.' + ELEM_PACK)[0] && setFirst.next()[0]) {
									setPackLast.removeClass(ELEM_LINE_SHORT);
								};
							} else {
								if (!setFirst.hasClass(ELEM_EXTEND)) {
									setFirst.addClass(ELEM_EXTEND);
								};
								//子节点添加延伸线
								setFirst.find('.' + ELEM_PACK).each(function() {
									$(this).children('.' + ELEM_SET).last().addClass(ELEM_LINE_SHORT);
								});
								//若是最外层,要始终保持相连的状态
								// if(!setFirst.parent('.'+ELEM_PACK)[0] && setFirst.next()[0]){
								//   //setFirst.children('.'+ELEM_PACK).children('.'+ELEM_SET).last().removeClass(ELEM_LINE_SHORT);
								// };
							};
							//若移到最外层
							if (!setFirst[0]) {
								//隐藏前置连接线
								setParent.addClass('layui-tree-setHide');
								setParent.children('.' + ELEM_PACK).children('.' + ELEM_SET).last().removeClass(ELEM_LINE_SHORT);
							};
						};
						//开启复选框且有父节点,同步新增节点状态
						if (setFirst[0] && options.showCheckbox) {
							if (setFirst.children('.' + ELEM_ENTRY).find('input[name="layuiTreeCheck"]')[0].checked) {
								var packLast = setParent.children('.' + ELEM_ENTRY);
								packLast.find('input[name="layuiTreeCheck"]+').click();
							};
						};
						options.dragend && options.dragend('拖拽成功,插入目标节点上方', setParent, $(this));
						return false;

						//若位于最下方
					} else if (disY > maxTop) {
						that.elem.children('.' + ELEM_SET).last().children('.' + ELEM_PACK).addClass(ELEM_SHOW);
						that.elem.append(setParent);
						setDel(parentSet);
						//最外层保持连接
						setParent.prev().children('.' + ELEM_PACK).children('.' + ELEM_SET).last().removeClass(ELEM_LINE_SHORT);
						//隐藏前置连接线
						setParent.addClass('layui-tree-setHide');
						//最后一个子节点加延伸
						setParent.children('.' + ELEM_PACK).children('.' + ELEM_SET).last().addClass(ELEM_LINE_SHORT);
						options.dragend && options.dragend('拖拽成功,插入最外层节点', setParent, that.elem);
						return false;
					};
				};
			});
		});
	};

	//部分事件
	Class.prototype.events = function() {
		var that = this,
			options = that.config,
			checkWarp = that.elem.find('.layui-tree-checkedFirst');

		//初始选中
		layui.each(checkWarp, function(i, item) {
			$(item).children('.' + ELEM_ENTRY).find('input[name="layuiTreeCheck"]+').trigger('click');
		});

		//搜索
		that.elem.find('.layui-tree-search').on('keyup', function() {
			var input = $(this),
				val = input.val(),
				pack = input.nextAll(),
				arr = [];

			//遍历所有的值
			pack.find('.' + ELEM_TEXT).each(function() {
				var entry = $(this).parents('.' + ELEM_ENTRY);
				//若值匹配,加一个类以作标识
				if ($(this).html().indexOf(val) != -1) {
					arr.push($(this).parent());

					var select = function(div) {
						div.addClass('layui-tree-searchShow');
						//向上父节点渲染
						if (div.parent('.' + ELEM_PACK)[0]) {
							select(div.parent('.' + ELEM_PACK).parent('.' + ELEM_SET));
						};
					};
					select(entry.parent('.' + ELEM_SET));
				};
			});

			//根据标志剔除
			pack.find('.' + ELEM_ENTRY).each(function() {
				var parent = $(this).parent('.' + ELEM_SET);
				if (!parent.hasClass('layui-tree-searchShow')) {
					parent.addClass(HIDE);
				};
			});
			if (pack.find('.layui-tree-searchShow').length == 0) {
				that.elem.append(that.elemNone);
			};

			//节点过滤的回调
			options.onsearch && options.onsearch({
				elem: arr
			});
		});

		//还原搜索初始状态
		that.elem.find('.layui-tree-search').on('keydown', function() {
			$(this).nextAll().find('.' + ELEM_ENTRY).each(function() {
				var parent = $(this).parent('.' + ELEM_SET);
				parent.removeClass('layui-tree-searchShow ' + HIDE);
			});
			if ($('.layui-tree-emptyText')[0]) $('.layui-tree-emptyText').remove();
		});
	};

	//得到选中节点
	Class.prototype.getChecked = function() {
		var that = this,
			options = that.config,
			checkId = [],
			checkData = [];
		//遍历节点找到选中索引
		$(options.elem).find('.layui-form-checked').each(function() {
			//如果是叶子节点,则直接放入
			var pSpan = $(this).prev().prev().find('.layui-icon');
			if (pSpan.hasClass('layui-icon-file')) {
				checkId.push(parseInt($(this).prev()[0].value));
			} else {
				//如果不是叶子节点,判断其子节点复选框个数与被选中子节点复选框个数是否相等
				var child = $(this).parents('.' + ELEM_ENTRY).eq(0).next();
				var ckCount = child.find('.layui-form-checkbox').length;
				var ckdCount = child.find('.layui-form-checked').length;
				if (ckCount == ckdCount) {
					checkId.push(parseInt($(this).prev()[0].value));
				}
			}

		});
		return checkId;
	};

	//设置选中节点
	Class.prototype.setChecked = function(checkedId, clearOther) {
		var that = this,
			options = that.config;
		clearOther = clearOther || true; //默认清除其他
		//清除其他
		if (clearOther) {
			$(options.elem).find('.layui-form-checked').prev('input[name="layuiTreeCheck"]').prop('checked', false);
		}
		//若返回数字
		var checkedArr = [];
		if (typeof checkedId === 'number') {
			checkedArr.push(checkedId);
		} else {
			checkedArr = checkedId;
		};
		options.checkedId = checkedArr;
		//初始选中
		for (let i = 0; i < checkedArr.length; i++) {
			let dataid = checkedArr[i];
			var input = $(options.elem).find('input[value="' + dataid + '"]');
			if (input.length > 0 && !input[0].checked) { //若未选中
				input.prop('checked', true);
				input.parents('.' + ELEM_PACK).prev().find('input[name="layuiTreeCheck"]').each(function() {
					this.checked = true;
				});
			}
		}
		that.renderCheckbox();
	};

	//展开指定节点
	var time;
	Class.prototype.expand = function() {
		var that = this,
			options = that.config;
		var ICONS = options.icons || {
			ICON_ADD: ICON_ADD,
			ICON_SUB: ICON_SUB,
			ICON_FILE: 'layui-icon-file'
		};
		if (options.expandAll) {
			$(options.elem).find('.' + ELEM_PACK).slideDown(200);
			$(options.elem).find('.' + ICONS.ICON_ADD).addClass(ICONS.ICON_SUB).removeClass(ICONS.ICON_ADD);
		} else {
			var expand = function() {
				var addNodes = $(options.elem).find('.' + ICONS.ICON_ADD); //待展开所有节点
				if (addNodes.length == 0) {
					//展开所有后关闭计时器
					// alert('已全部展开!');
					that.config.expandAll = true;
					clearInterval(time);
					var successEvent = that.config.expandSuccess;
					successEvent ? successEvent() : '';
					return;
				}
				for (let i = 0; i < addNodes.length; i++) {
					if (addNodes.eq(i).hasClass(ICONS.ICON_ADD)) {
						addNodes.eq(i).trigger('click');
					}
				}
			}
			time = setInterval(expand, 400);
		}
	};

	//折叠指定节点
	Class.prototype.fold = function() {
		if (time != null) {
			clearInterval(time);
		}
		var that = this,
			options = that.config;
		var ICONS = options.icons || {
			ICON_ADD: ICON_ADD,
			ICON_SUB: ICON_SUB,
			ICON_FILE: 'layui-icon-file'
		};
		$(options.elem).find('.' + ELEM_PACK).hide();
		$(options.elem).find('.' + ICONS.ICON_SUB).addClass(ICONS.ICON_ADD).removeClass(ICONS.ICON_SUB);
	}

	//记录所有实例
	thisModule.that = {}; //记录所有实例对象
	thisModule.config = {}; //记录所有实例配置项

	//重载实例
	treelazy.reload = function(id, options) {
		var that = thisModule.that[id];
		that.reload(options);

		return thisModule.call(that);
	};

	//获得选中的节点数据
	treelazy.getChecked = function(id) {
		var that = thisModule.that[id];
		return that.getChecked();
	};

	//设置选中节点
	treelazy.setChecked = function(id, checkedId, clear) {
		var that = thisModule.that[id];
		return that.setChecked(checkedId, clear);
	};

	//展开指定节点
	treelazy.expand = function(id) {
		var that = thisModule.that[id];
		return that.expand();
	};

	//折叠指定节点
	treelazy.fold = function(id) {
		var that = thisModule.that[id];
		return that.fold();
	};
	treelazy.select = function(options) {
		console.log(options);
	};
	//核心入口
	treelazy.render = function(options) {
		var inst = new Class(options);
		return thisModule.call(inst);
	};

	//核心入口
	treelazy.select = function(options) {
		var inst = new Class(options);
		return thisModule.call(inst);
	}
	exports(MOD_NAME, treelazy);
})

相关CSS样式

/* layui表格中的下拉框样式 */
.layui-table-select input {
	border: none;
}

.layui-table-select input:hover {
	border-color: #008CBA !important;
}

.layui-table-select-anim dl {
	border: none;
	border-top: 1px solid #E9E9E9;
	box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
}

.layui-table-select-anim dl dd {
	overflow: overlay;
}

.layui-table-select-anim dl dd:hover {
	background: white !important;
}

/* 滚动条高宽 */
.layui-table-select-anim dl dd::-webkit-scrollbar {
	width: 10px;
}

/* 滚动条里面滑块 */
.layui-table-select-anim dl dd::-webkit-scrollbar-thumb {
	border-radius: 10px 2px 2px 10px;
	-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
	background: rgba(0, 0, 0, 0.2);
}

/* 滚动条里面轨道 */
.layui-table-select-anim dl dd::-webkit-scrollbar-track {
	border-radius: 10px 2px 2px 10px;
	-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
	background: rgba(0, 0, 0, 0.1);
}
/**** layui下拉树样式 ****/
.layui-treeselect dl dd {
	background: white;
	color: #555;
	overflow: auto;
}

.layui-treeselect dl dd.layui-this {
	background: white;
	color: #555;
}

.layui-treeselect dl dd:hover {
	background: white;
}

.layui-treeselect .layui-input {
	color: #666;
}

.layui-treeselect .layui-disabled {
	background: #F6F6F6;
	color: #999 !important;
}

/* 滚动条样式 */
/* 滚动条高宽 */
.layui-treeselect dl dd{
	overflow: overlay;
}
.layui-treeselect dl dd::-webkit-scrollbar {
	width: 10px;
}

/* 滚动条里面滑块 */
.layui-treeselect dl dd::-webkit-scrollbar-thumb {
	border-radius: 10px 2px 2px 10px;
	-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
	background: rgba(0, 0, 0, 0.2);
}

/* 滚动条里面轨道 */
.layui-treeselect dl dd::-webkit-scrollbar-track {
	border-radius: 10px 2px 2px 10px;
	-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
	background: rgba(0, 0, 0, 0.1);
}

一、layui表格中下拉树形组件:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<link rel="stylesheet" href="../layui-master/dist/css/layui.css" />
		<title>表格中部门选择下拉框</title>
		<style>
			html,
			body {
				overflow: hidden;
			}
		</style>
	</head>
	<body>
		<div class="layui-fluid">
			<div class="layui-row">
				<table id="table" lay-filter="table" class="layui-hide"></table>
			</div>
		</div>
	</body>
	<script src="../layui-master/dist/layui.js" charset="utf-8"></script>
	<script>
		var tableID = "table";
		layui.config({
			base: '../../page/modules/'
		}).extend({
			treelazy: 'customcomponents/treelazy'
		}).use(['layer', 'table', 'treelazy'], function() {
			var $ = layui.$,
				layer = layui.layer,
				treelazy = layui.treelazy,
				table = layui.table;


			//初始化渲染表格
			var datas = [];
			for (let i = 0; i < 20; i++) {
				datas.push({
					id: i + 1
				});
			}
			var tableIns = table.render({
				elem: '#' + tableID,
				height: 'full-1',
				size: 'sm',
				limit: 100,
				page: true,
				cols: [
					[{
							type: 'numbers'
						},
						{
							field: 'id',
							title: 'ID'
						},
						{
							field: 'name',
							title: '人员名称',
							edit: 'text'
						},
						{
							field: 'wsid',
							title: '部门',
							event: 'wsidEvent'
						},
						{
							field: 'memo',
							title: '备注'
						}
					]
				],
				data: datas
			});
			/********* 监听区 ********/
			table.on('row(table)', function(obj) {
				obj.tr.addClass("layui-table-click").siblings().removeClass("layui-table-click");
			});
			table.on('tool(' + tableID + ')', function(obj) {
				var data = obj.data,
					event = obj.event,
					tr = obj.tr; //获得当前行 tr 的DOM对象;
				switch (event) {
					case 'wsidEvent':
						treelazy.tabletreeselect({
							tableID: tableID,
							td: $(this),
							colName: 'wsid',
							load: function(node, render) {
								var pid = 0;
								if (node.level > 0) {
									pid = node.data.id;
								}
								if (node.level == 0) {
									render([{
										id: 1,
										text: '一级部门',
										leaf: false
									}, {
										id: 2,
										text: '一级部门',
										leaf: false
									}, {
										id: 3,
										text: '一级部门',
										leaf: false
									}, {
										id: 4,
										text: '一级部门',
										leaf: false
									}, {
										id: 5,
										text: '一级部门',
										leaf: false
									}]);
								}
								if (node.level == 1) {
									render([{
										id: 22,
										text: '二级部门1',
										leaf: true
									}, {
										id: 33,
										text: '二级部门2',
										leaf: true
									}]);
								}
							},
							click: function(obj) {
								// console.log(obj.data);
							}
						});
						break;
				}
			});
		});
	</script>
</html>

二、css样式:

/**** layui下拉树样式 ****/
.layui-treeselect dl dd {
	background: white;
	color: #555;
	overflow: auto;
}

.layui-treeselect dl dd.layui-this {
	background: white;
	color: #555;
}

.layui-treeselect dl dd:hover {
	background: white;
}

.layui-treeselect .layui-input {
	color: #666;
}

.layui-treeselect .layui-disabled {
	background: #F6F6F6;
	color: #999 !important;
}

/* 滚动条样式 */
/* 滚动条高宽 */
.layui-treeselect dl dd{
	overflow: overlay;
}
.layui-treeselect dl dd::-webkit-scrollbar {
	width: 10px;
}

/* 滚动条里面滑块 */
.layui-treeselect dl dd::-webkit-scrollbar-thumb {
	border-radius: 10px 2px 2px 10px;
	-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
	background: rgba(0, 0, 0, 0.2);
}

/* 滚动条里面轨道 */
.layui-treeselect dl dd::-webkit-scrollbar-track {
	border-radius: 10px 2px 2px 10px;
	-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
	background: rgba(0, 0, 0, 0.1);
}
/* layui表格中的下拉框样式 */
.layui-table-select input {
	border: none;
}

.layui-table-select input:hover {
	border-color: #008CBA !important;
}

.layui-table-select-anim dl {
	border: none;
	border-top: 1px solid #E9E9E9;
	box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
}

.layui-table-select-anim dl dd {
	overflow: overlay;
}

.layui-table-select-anim dl dd:hover {
	background: white !important;
}

/* 滚动条高宽 */
.layui-table-select-anim dl dd::-webkit-scrollbar {
	width: 10px;
}

/* 滚动条里面滑块 */
.layui-table-select-anim dl dd::-webkit-scrollbar-thumb {
	border-radius: 10px 2px 2px 10px;
	-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
	background: rgba(0, 0, 0, 0.2);
}

/* 滚动条里面轨道 */
.layui-table-select-anim dl dd::-webkit-scrollbar-track {
	border-radius: 10px 2px 2px 10px;
	-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
	background: rgba(0, 0, 0, 0.1);
}