/* * @Author: Jeffrey Wang * @Date: 2018-03-16 18:24:47 * @Version: v1.2.4 * @Last Modified by: Jeffrey Wang * @Last Modified time: 2019-04-29 14:33:00 */ // 节点树 layui.define(['jquery', 'form'], function (exports) { var $ = layui.jquery; var form = layui.form; var MOD_NAME = 'authtree'; var obj = { // 渲染 + 绑定事件 openIconContent: '', closeIconContent: '', // 表单类型 checkbox: 多选,radio:单选 checkType: 'checkbox', // 选中、半选中、未选中 checkedIconContent: '', halfCheckedIconContent: '', notCheckedIconContent: '', // 保存节点数据 checkedNode: {}, notCheckedNode: {}, // 临时保存最新操作影响的节点 lastCheckedNode: {}, lastNotCheckedNode: {}, // 已经渲染过的树,可用来获取配置,{ dst: {trees: '树的节点数据', opt: '配置'} } renderedTrees: {}, // 使用 layui 的监听事件 on: function (events, callback) { return layui.onevent.call(this, MOD_NAME, events, callback); }, /** * 渲染DOM并绑定事件 * @param {[type]} dst [目标ID,如:#test1] * @param {[type]} trees [数据,格式:{}] * @param {[type]} inputname [上传表单名] * @param {[type]} layfilter [lay-filter的值] * @param {[type]} openall [是否展开全部] * @return {[type]} [description] */ render: function (dst, trees, opt) { // 表单名称配置 var inputname = opt.inputname ? opt.inputname : 'menuids[]'; opt.inputname = inputname; // lay-filter 配置 var layfilter = opt.layfilter ? opt.layfilter : 'checkauth'; opt.layfilter = layfilter; // 默认展开全部 配置 var openall = opt.openall ? opt.openall : false; opt.openall = openall; // 双击展开此层配置 var dblshow = opt.dblshow ? opt.dblshow : false; opt.dblshow = dblshow; // 双击时间差 - 不能设置过长,否则单击延迟很感人 var dbltimeout = opt.dbltimeout ? opt.dbltimeout : 120; opt.dbltimeout = dbltimeout; // 默认展开有选中数据的层 var openchecked = typeof opt.openchecked !== 'undefined' ? opt.openchecked : true; opt.openchecked = openchecked; // 自动取消选中 var autoclose = typeof opt.autoclose !== 'undefined' ? opt.autoclose : true; opt.autoclose = autoclose; // 自动选择直属父级节点 var autochecked = typeof opt.autochecked !== 'undefined' ? opt.autochecked : true; opt.autochecked = autochecked; // 是否隐藏左侧 单选/多选的选框 -- 特殊需求,一般用于单选树并且不用 var hidechoose = typeof opt.hidechoose !== 'undefined' ? opt.hidechoose : false; opt.hidechoose = hidechoose; // 是否开启半选 var halfchoose = typeof opt.halfchoose !== 'undefined' ? opt.halfchoose : false; opt.halfchoose = halfchoose; // 收起叶子节点(排列于一行) var collapseLeafNode = typeof opt.collapseLeafNode !== 'undefined' ? opt.collapseLeafNode : false; opt.collapseLeafNode = collapseLeafNode; // 有子节点的前显字符配置 opt.prefixChildStr = opt.prefixChildStr ? opt.prefixChildStr : '├─'; // 单选、多选配置 opt.checkType = opt.checkType ? opt.checkType : 'checkbox'; this.checkType = opt.checkType; // 皮肤可选择 opt.checkSkin = opt.checkSkin ? opt.checkSkin : 'primary'; // 主题定制 opt.theme = opt.theme ? opt.theme : ''; opt.themePath = opt.themePath ? opt.themePath : 'catch-admin/assets/module/authtree/tree_themes/'; // 展开、折叠节点的前显字符配置 opt.openIconContent = opt.openIconContent ? opt.openIconContent : ''; this.openIconContent = opt.openIconContent; opt.closeIconContent = opt.closeIconContent ? opt.closeIconContent : ''; this.closeIconContent = opt.closeIconContent; // 选中、半选中、未选中节点的图标配置 opt.checkedIconContent = opt.checkedIconContent ? opt.checkedIconContent : '\e605'; this.checkedIconContent = opt.checkedIconContent; opt.halfCheckedIconContent = opt.halfCheckedIconContent ? opt.halfCheckedIconContent : '\e605'; this.halfCheckedIconContent = opt.halfCheckedIconContent; opt.notCheckedIconContent = opt.notCheckedIconContent ? opt.notCheckedIconContent : ''; this.notCheckedIconContent = opt.notCheckedIconContent; // 渲染配置参数 opt.checkedKey = opt.checkedKey ? opt.checkedKey : 'checked'; opt.childKey = opt.childKey ? opt.childKey : 'list'; opt.disabledKey = opt.disabledKey ? opt.disabledKey : 'disabled'; opt.nameKey = opt.nameKey ? opt.nameKey : 'name'; opt.valueKey = opt.valueKey ? opt.valueKey : 'value'; // 不启用双击展开,单击不用延迟 var dblisten = true; if (dblshow) { // 开启双击展开,双击事件默认为120s } else { // 未开启双击展开且 dbltimeout <= 0,则说明不用监听双击事件 if (opt.dbltimeout <= 0) { dblisten = false; } dbltimeout = 0; // opt.dbltimeout = dbltimeout; } // 记录渲染过的树 obj.renderedTrees[dst] = {trees: trees, opt: opt}; // 主题定制 if (typeof opt.theme === 'string' && opt.theme !== '') { $(dst).addClass(opt.theme) layui.link(opt.themePath + opt.theme + '.css') } if (opt.hidechoose) { $(dst).addClass('auth-tree-hidechoose'); } $(dst).html(obj.renderAuth(trees, 0, { inputname: inputname, layfilter: layfilter, openall: openall, openchecked: openchecked, checkType: this.checkType, prefixChildStr: opt.prefixChildStr, // 配置参数 checkedKey: opt.checkedKey, childKey: opt.childKey, disabledKey: opt.disabledKey, nameKey: opt.nameKey, valueKey: opt.valueKey, collapseLeafNode: opt.collapseLeafNode, })); if (openchecked) { obj.showChecked(dst); } form.render(); // 变动则存一下临时状态 obj._saveNodeStatus(dst); // 开启自动宽度优化 obj.autoWidthAll(); // 备注:如果使用form.on('checkbox()'),外部就无法使用form.on()监听同样的元素了(LAYUI不支持重复监听了)。 // form.on('checkbox('+layfilter+')', function(data){ // /*属下所有权限状态跟随,如果选中,往上走全部选中*/ // var childs = $(data.elem).parent().next().find('input[type="checkbox"]').prop('checked', data.elem.checked); // if(data.elem.checked){ // /*查找child的前边一个元素,并将里边的checkbox选中状态改为true。*/ // $(data.elem).parents('.auth-child').prev().find('input[type="checkbox"]').prop('checked', true); // } // /*console.log(childs);*/ // form.render('checkbox'); // }); // 解决单击和双击冲突问题的 timer 变量 var timer = 0; $(dst).find('.auth-single:first').unbind('click').on('click', '.layui-form-checkbox,.layui-form-radio', function (event) { // window.event? window.event.cancelBubble = true : event.stopPropagation(); var that = this; clearTimeout(timer); // 双击判断需要的延迟处理 timer = setTimeout(function () { var elem = $(that).prev(); var checked = elem.is(':checked'); if (autochecked) { if (checked) { /*查找child的前边一个元素,并将里边的checkbox选中状态改为true。*/ elem.parents('.auth-child').prev().find('.authtree-checkitem:not(:disabled)[type="checkbox"]').prop('checked', true); } elem.parent().next().find('.authtree-checkitem:not(:disabled)[type="checkbox"]').prop('checked', checked); } if (autoclose) { if (checked) { // pass } else { // 自动关闭父级选中节点 obj._autoclose($(that).parent()); } } form.render('checkbox'); form.render('radio'); // 变动则存一下临时状态 obj._saveNodeStatus(dst); // 触发 change 事件 obj._triggerEvent(dst, 'change', { othis: $(that), oinput: elem, value: elem.val(), }); obj.autoWidthAll(); }, dbltimeout); return false; }); /*动态绑定展开事件*/ $(dst).unbind('click').on('click', '.auth-icon', function () { obj.iconToggle(dst, this); }); /*双击展开*/ $(dst).find('.auth-single:first').unbind('dblclick').on('dblclick', '.layui-form-checkbox,.layui-form-radio', function (e) { // 触发时间 > 0,才触发双击事件 // opt.dbltimeout 是用户真实设定的超时时间,与 dbltimeout 不一样 // if (opt.dbltimeout > 0) { obj._triggerEvent(dst, 'dblclick', { othis: $(this), elem: $(this).prev(), value: $(this).prev().val(), }); // } if (dblshow) { clearTimeout(timer); obj.iconToggle(dst, $(this).prevAll('.auth-icon:first')); } }).on('selectstart', function () { // 屏蔽双击选中文字 return false; }); }, // 自动关闭 - 如果兄弟节点均没选中,递归取消上级元素选中状态,传入的是 .auth-status 节点,递归 .auth-status 上级节点 _autoclose: function (obj) { var single = $(obj).parent().parent(); var authStatus = single.parent().prev(); if (!authStatus.hasClass('auth-status')) { return false; } // 仅一层 if (single.find('div>.auth-status>input.authtree-checkitem:not(:disabled)[type="checkbox"]:checked').length === 0) { authStatus.find('.authtree-checkitem:not(:disabled)[type="checkbox"]').prop('checked', false); this._autoclose(authStatus); } }, // 以 icon 的维度,切换显示下级空间 iconToggle: function (dst, iconobj) { var origin = $(iconobj); var child = origin.parent().parent().find('.auth-child:first'); if (origin.is('.active')) { /*收起*/ origin.removeClass('active').html(obj.closeIconContent); child.slideUp('fast'); } else { /*展开*/ origin.addClass('active').html(obj.openIconContent); child.slideDown('fast'); } obj._triggerEvent(dst, 'deptChange'); return false; }, // 递归创建格式 renderAuth: function (tree, dept, opt) { var inputname = opt.inputname; var layfilter = opt.layfilter; var openall = opt.openall; var str = '