2023-03-24 14:33:36 +08:00

2120 lines
67 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 仿element-ui级联选择器
* 已实现单选、多选、无关联选择
* 其他功能:组件禁用、节点禁用、自定义属性、自定义空面板提示,自定义无选择时的提示、多选标签折叠、回显、搜索、动态加载、最大选中数量限制、禁用项固定等操作。
* element-ui没有的功能最大选中数量限制、禁用项固定
* author: yixiaco
* gitee: https://gitee.com/yixiacoco/lay_cascader
* github: https://github.com/yixiaco/lay_cascader
*/
;!function (e) {
var src = e.document.currentScript.src;
var groupMatch = /(\S*\/)cascader(\.min)?\.js(\?.*)?/i.exec(src);
if (groupMatch && groupMatch.length >= 2 && (!groupMatch[3] || groupMatch[3].indexOf('css=true') !== -1)) {
layui.link(groupMatch[1] + 'cascader' + (groupMatch[2] || '') + '.css');
}
}(window);
layui.define(["jquery"], function (exports) {
var $ = layui.jquery;
/**
* 阻止事件冒泡
* @param event
*/
function stopPropagation(event) {
event = event || window.event
if (event.stopPropagation) {
event.stopPropagation()
} else {
event.cancelBubble = true
}
}
/**
* 级联各项节点对象
* @param data 原始对象信息
* @param cascader 级联对象
* @param level 层级从0开始
* @param parentNode 父节点对象
* @constructor
*/
function Node(data, cascader, level, parentNode) {
this.data = data;
this.cascader = cascader;
this.config = cascader.config;
this.props = cascader.props;
this.level = level;
this.parentNode = parentNode;
// 引入的icon图标
this.icons = cascader.icons;
//该节点是否被选中 0:未选中1选中2不定
this._checked = 0;
// 是否正在加载中
this._loading = false;
// 每个Node的唯一标识
this.nodeId = cascader.data.nodeId++;
}
Node.prototype = {
constructor: Node,
/** 最顶级父节点 */
get topParentNode() {
return !this.parentNode && this || this.topParentNode;
},
/** 子节点 */
childrenNode: undefined,
get loading() {
return this._loading;
},
set loading(loading) {
var $li = this.$li;
if ($li) {
var rightIcon = this.icons.right;
var loadingIcon = this.icons.loading;
var $i = $li.find('i');
if (loading) {
$i.addClass(loadingIcon);
$i.removeClass(rightIcon);
} else {
$i.addClass(rightIcon);
$i.removeClass(loadingIcon);
}
}
return this._loading = loading;
},
/** 当前节点的显示文本 */
get label() {
return this.data[this.props.label];
},
/** 当前节点的值 */
get value() {
return this.data[this.props.value];
},
/** 是否禁用 */
get disabled() {
var multiple = this.props.multiple;
var maxSize = this.config.maxSize;
var checkedNodeIds = this.cascader.data.checkedNodeIds;
var disabledName = this.props.disabled;
var checkStrictly = this.props.checkStrictly;
// 检查是否超过最大值限制
if (multiple && maxSize !== 0) {
if (checkedNodeIds.length >= maxSize && checkedNodeIds.indexOf(this.nodeId) === -1) {
// 如果是关联的多选,需要查询叶子节点是否有被选中的项
if (!checkStrictly) {
var leafChildren = this.getAllLeafChildren();
var nodeIds = leafChildren.map(function (value) {
return value.nodeId
});
// 如果叶子节点不包含则直接返回true
if (!nodeIds.some(function (nodeId) {
return checkedNodeIds.indexOf(nodeId) !== -1;
})) {
return true;
}
} else {
return true;
}
}
}
if (!checkStrictly) {
var path = this.path;
return path.some(function (node) {
return node.data[disabledName];
});
} else {
return this.data[disabledName];
}
},
/** 子节点数据 */
get children() {
return this.data[this.props.children];
},
set children(children) {
this.data[this.props.children] = children;
},
/** 叶子节点 */
get leaf() {
var leaf = this.data[this.props.leaf];
if (typeof leaf === 'boolean') {
return leaf;
}
// 如果children不为空,则判断是否是子节点
if (this.children) {
return this.children.length <= 0;
}
return true;
},
/** 当前单选值 */
get activeNodeId() {
return this.cascader.data.activeNodeId;
},
/** 当前复选框值 */
get checkedNodeIds() {
return this.cascader.data.checkedNodeIds;
},
/** 路径 */
get path() {
var parentNode = this.parentNode;
if (parentNode) {
return parentNode.path.concat([this]);
} else {
return [this];
}
},
/** 是否正在搜索中 */
get isFiltering() {
return this.cascader.isFiltering;
},
/** 输入框的tag标签 */
get $tag() {
var cascader = this.cascader;
var showAllLevels = this.config.showAllLevels;
var disabled = this.config.disabled;
var nodeDisabled = this.disabled;
var disabledFixed = this.config.disabledFixed;
var label = this.getPathLabel(showAllLevels);
var $tag = cascader.get$tag(label, !disabled && (!nodeDisabled || !disabledFixed));
var self = this;
$tag.find('i').click(function (event) {
stopPropagation(event);
self.selectedValue();
cascader.removeTag(self.value, self);
});
return $tag;
},
/**
* 完整路径的标签
* @param showAllLevels
* @returns {string}
*/
getPathLabel: function (showAllLevels) {
var path = this.path;
var separator = this.config.separator;
var label;
if (showAllLevels) {
label = path.map(function (node) {
return node.label;
}).join(separator);
} else {
label = path[path.length - 1].label;
}
return label;
},
/**
* 初始化
*/
init: function () {
var multiple = this.props.multiple;
var checkStrictly = this.props.checkStrictly;
var fromIcon = this.icons.from;
var rightIcon = this.icons.right;
var icon = '';
var label = this.label;
if (!this.leaf) {
icon = rightIcon;
}
this.$li = $('<li role="menuitem" id="cascader-menu" tabindex="-1" class="el-cascader-node" aria-haspopup="true" aria-owns="cascader-menu"><span class="el-cascader-node__label">' + label + '</span><i class="' + fromIcon + ' ' + icon + '"></i></li>');
// 节点渲染
if (!multiple && !checkStrictly) {
this._renderRadio();
} else if (!multiple && checkStrictly) {
this._renderRadioCheckStrictly();
} else if (multiple && !checkStrictly) {
this._renderMultiple();
} else if (multiple && checkStrictly) {
this._renderMultipleCheckStrictly();
}
},
/**
* 初始化可搜索li
*/
initSuggestionLi: function () {
var label = this.getPathLabel(true);
this.$suggestionLi = $('<li tabindex="-1" class="el-cascader__suggestion-item"><span>' + label + '</span></li>');
// 节点渲染
this._renderFiltering();
},
/**
* 绑定到菜单中
* @param $list li节点
*/
bind: function ($list) {
this.init();
$list.append(this.$li);
},
/**
* 绑定可搜索到列表中
* @param $list
*/
bindSuggestion: function ($list) {
this.initSuggestionLi();
$list.append(this.$suggestionLi);
},
/**
* 可搜索渲染
* @private
*/
_renderFiltering: function () {
var $li = this.$suggestionLi;
var nodeId = this.nodeId;
var fromIcon = this.icons.from;
var okIcon = this.icons.ok;
var self = this;
var cascader = this.cascader;
var multiple = this.props.multiple;
var icon = '<i class="' + fromIcon + ' ' + okIcon + ' el-icon-check"></i>';
$li.click(function (event) {
stopPropagation(event);
self.selectedValue();
if (multiple) {
if (self.checkedNodeIds.indexOf(nodeId) === -1) {
$li.removeClass('is-checked');
$li.find('.el-icon-check').remove();
} else {
$li.addClass('is-checked');
$li.append(icon);
}
} else {
// 关闭面板
cascader.close();
}
});
if (multiple && self.checkedNodeIds.indexOf(nodeId) !== -1
|| !multiple && self.activeNodeId === nodeId) {
$li.addClass('is-checked');
$li.append(icon)
}
},
/**
* 单选&&关联
* @private
*/
_renderRadio: function () {
var $li = this.$li;
var nodeId = this.nodeId;
var fromIcon = this.icons.from;
var okIcon = this.icons.ok;
var level = this.level;
var leaf = this.leaf;
var self = this;
var cascader = this.cascader;
var activeNode = this.cascader.data.activeNode;
var parentNode = this.parentNode;
if (self.activeNodeId && activeNode.path.some(function (node) {
return node.nodeId === nodeId;
})) {
if (self.activeNodeId === nodeId) {
$li.prepend('<i class="' + fromIcon + ' ' + okIcon + ' el-cascader-node__prefix"></i>');
}
$li.addClass('is-active');
$li.addClass('in-checked-path');
}
// 是否禁用
if (this.disabled) {
$li.addClass('is-disabled');
return;
}
$li.addClass('is-selectable');
if (parentNode) {
parentNode.$li.siblings().removeClass('in-active-path');
parentNode.$li.addClass('in-active-path');
}
// 触发下一个节点
this._liClick(function (event) {
stopPropagation(event);
var childrenNode = self.childrenNode;
if (leaf && event.type === 'click') {
self.selectedValue();
// 关闭面板
cascader.close();
}
// 添加下级菜单
cascader._appendMenu(childrenNode, level + 1, self);
});
},
/**
* 单选&&非关联
* @private
*/
_renderRadioCheckStrictly: function () {
var $li = this.$li;
var nodeId = this.nodeId;
var level = this.level;
var leaf = this.leaf;
var self = this;
var cascader = this.cascader;
var activeNode = cascader.data.activeNode;
var parentNode = this.parentNode;
$li.addClass('is-selectable');
// 任意一级单选
var $radio = $('<label role="radio" tabindex="0" class="el-radio"><span class="el-radio__input"><span class="el-radio__inner"></span><input type="radio" aria-hidden="true" tabindex="-1" class="el-radio__original" value="' + nodeId + '"></span><span class="el-radio__label"><span></span></span></label>');
this.$radio = $radio;
$li.prepend($radio);
if (parentNode) {
parentNode.$li.siblings().removeClass('in-active-path');
parentNode.$li.addClass('in-active-path');
}
// 触发下一个节点
this._liClick(function (event) {
stopPropagation(event);
var childrenNode = self.childrenNode;
if (!self.disabled && leaf && event.type === 'click') {
self.selectedValue();
}
// 添加下级菜单
cascader._appendMenu(childrenNode, level + 1, self);
});
if (self.activeNodeId && activeNode.path.some(function (node) {
return node.nodeId === nodeId;
})) {
if (self.activeNodeId === nodeId) {
$radio.find('.el-radio__input').addClass('is-checked');
}
$li.addClass('is-active');
$li.addClass('in-checked-path');
}
if (this.disabled) {
$radio.addClass('is-disabled');
$radio.find('.el-radio__input').addClass('is-disabled');
return;
}
// 选中事件
$radio.click(function (event) {
event.preventDefault();
!leaf && self.selectedValue();
});
},
/**
* 多选&&关联
* @private
*/
_renderMultiple: function () {
var $li = this.$li;
var level = this.level;
var leaf = this.leaf;
var self = this;
var cascader = this.cascader;
var checked = this._checked;
var parentNode = this.parentNode;
$li.addClass('el-cascader-node');
// 多选框
var $checked = $('<label class="el-checkbox"><span class="el-checkbox__input"><span class="el-checkbox__inner"></span><input type="checkbox" aria-hidden="false" class="el-checkbox__original" value=""></span></label>');
this.$checked = $checked;
$li.prepend($checked);
// 渲染
if (checked === 1) {
this.$checked.find('.el-checkbox__input').addClass('is-checked');
} else if (checked === 2) {
this.$checked.find('.el-checkbox__input').addClass('is-indeterminate');
}
if (parentNode) {
parentNode.$li.siblings().removeClass('in-active-path');
parentNode.$li.addClass('in-active-path');
}
// 触发下一个节点
this._liClick(function (event) {
stopPropagation(event);
var childrenNode = self.childrenNode;
if (!self.disabled && leaf && event.type === 'click') {
// 最后一级就默认选择
self.selectedValue();
}
// 添加下级菜单
cascader._appendMenu(childrenNode, level + 1, self);
});
if (this.disabled) {
$li.addClass('is-disabled');
$checked.addClass('is-disabled');
$checked.find('.el-checkbox__input').addClass('is-disabled');
return;
}
// 选中事件
$checked.click(function (event) {
event.preventDefault();
if (!leaf) {
var childrenNode = self.childrenNode;
self.selectedValue();
cascader._appendMenu(childrenNode, level + 1, self);
}
});
},
/**
* 多选&&非关联
* @private
*/
_renderMultipleCheckStrictly: function () {
var $li = this.$li;
var level = this.level;
var leaf = this.leaf;
var self = this;
var cascader = this.cascader;
var checkedNodeIds = cascader.data.checkedNodeIds;
var checkedNodes = cascader.data.checkedNodes;
var nodeId = this.nodeId;
var parentNode = this.parentNode;
$li.addClass('el-cascader-node is-selectable');
// 多选框
var $checked = $('<label class="el-checkbox"><span class="el-checkbox__input"><span class="el-checkbox__inner"></span><input type="checkbox" aria-hidden="false" class="el-checkbox__original" value=""></span></label>');
this.$checked = $checked;
$li.prepend($checked);
// 渲染
var exist = checkedNodes.some(function (node) {
return node.path.some(function (node) {
return node.nodeId === nodeId;
})
});
if (exist) {
$li.addClass('in-checked-path');
if (checkedNodeIds.indexOf(nodeId) !== -1) {
this.$checked.find('.el-checkbox__input').addClass('is-checked');
}
}
if (parentNode) {
parentNode.$li.siblings().removeClass('in-active-path');
parentNode.$li.addClass('in-active-path');
}
// 触发下一个节点
this._liClick(function (event) {
stopPropagation(event);
var childrenNode = self.childrenNode;
if (!self.disabled && leaf && event.type === 'click') {
// 最后一级就默认选择
self.selectedValue();
}
// 添加下级菜单
cascader._appendMenu(childrenNode, level + 1, self);
});
if (this.disabled) {
$checked.addClass('is-disabled');
$checked.find('.el-checkbox__input').addClass('is-disabled');
return;
}
// 选中事件
$checked.click(function (event) {
event.preventDefault();
if (!leaf) {
self.selectedValue();
var childrenNode = self.childrenNode;
// 添加下级菜单
cascader._appendMenu(childrenNode, level + 1, self);
}
});
},
/**
* 向上传递
* @param callback 执行方法如果返回false则中断执行
* @param advance 是否先执行一次
* @param self 自身
*/
transferParent: function (callback, advance, self) {
if (!self) {
self = this;
}
if (this !== self || advance) {
var goOn = callback && callback(this);
if (goOn === false) {
return;
}
}
this.parentNode && this.parentNode.transferParent(callback, advance, self);
},
/**
* 向下传递
* @param callback 执行的方法如果返回false则中断执行
* @param advance 是否先执行一次
* @param self 自身
*/
transferChildren: function (callback, advance, self) {
if (!self) {
self = this;
}
if (this !== self || advance) {
var goOn = callback && callback(this);
if (goOn === false) {
return;
}
}
var children = this.getChildren();
if (children && children.length > 0) {
for (var index in children) {
children[index].transferChildren(callback, advance, self);
}
}
},
/**
* 设置级联值
*/
selectedValue: function () {
var nodeId = this.nodeId;
var cascader = this.cascader;
var multiple = this.props.multiple;
var checkStrictly = this.props.checkStrictly;
var leaf = this.leaf;
if (!multiple && (leaf || checkStrictly)) {
cascader._setActiveValue(nodeId, this);
} else if (multiple) {
var checkedNodeIds = cascader.data.checkedNodeIds;
var checkedNodes = cascader.data.checkedNodes;
var disabledFixed = this.config.disabledFixed;
var paths;
if (checkStrictly) {
var index = checkedNodeIds.indexOf(nodeId);
if (index === -1) {
paths = checkedNodes.concat([this]);
} else {
paths = checkedNodes.concat();
paths.splice(index, 1);
}
} else {
var allLeafChildren = this.getAllLeafChildren();
var checked;
if (this._checked !== 1 && disabledFixed) {
checked = this._getMultipleChecked(allLeafChildren);
} else {
checked = this._checked;
}
if (checked === 1) {
// 选中->未选中
paths = checkedNodes.filter(function (node1) {
return !allLeafChildren.some(function (node2) {
return node1.nodeId === node2.nodeId;
});
});
} else {
// 未选中、部分选中->选中
var add = allLeafChildren.filter(function (node) {
return checkedNodeIds.indexOf(node.nodeId) === -1;
});
paths = checkedNodes.concat(add);
}
}
var nodeIds = paths.map(function (node) {
return node.nodeId;
});
cascader._setCheckedValue(nodeIds, paths);
}
},
_liLoad: function (event, callback) {
var leaf = this.leaf;
var lazy = this.props.lazy;
var lazyLoad = this.props.lazyLoad;
var children = this.children;
var self = this;
var cascader = this.cascader;
var level = this.level;
var multiple = this.props.multiple;
var checkStrictly = this.props.checkStrictly;
if (!leaf && (!children || children.length === 0) && lazy) {
if (!self.loading) {
self.loading = true;
lazyLoad(self, function (nodes) {
self.loading = false;
self.setChildren(cascader.initNodes(nodes, level + 1, self));
self.children = nodes;
callback && callback(event);
// 多选&关联时,重新同步下父级节点的样式
multiple && !checkStrictly && self.transferParent(function (node) {
node.syncStyle();
}, true);
});
}
} else {
callback && callback(event);
}
},
/**
* 点击li事件
* @param callback
* @private
*/
_liClick: function (callback) {
var leaf = this.leaf;
var $li = this.$li;
var self = this;
function load(event) {
self._liLoad(event, callback);
}
if (this.props.expandTrigger === "click" || leaf) {
$li.click(load);
}
if (this.props.expandTrigger === "hover") {
$li.mouseenter(load);
}
},
setChildren: function (children) {
this.childrenNode = children;
},
getChildren: function () {
return this.childrenNode;
},
/**
* 同步样式
*/
syncStyle: function () {
var multiple = this.props.multiple;
var checkStrictly = this.props.checkStrictly;
if (multiple) {
//多选
if (checkStrictly) {
this._sync.syncMultipleCheckStrictly(this);
} else {
this._sync.syncMultiple(this);
}
} else {
//单选
if (checkStrictly) {
this._sync.syncRadioCheckStrictly(this);
} else {
this._sync.syncRadio(this);
}
}
},
/**
* 同步本节点样式
*/
_sync: {
/**
* 同步单选关联样式
*/
syncRadio: function (self) {
var $li = self.$li;
var fromIcon = self.icons.from;
var okIcon = self.icons.ok;
var multiple = self.props.multiple;
var checkStrictly = self.props.checkStrictly;
var nodeId = self.nodeId;
if (!$li || multiple || checkStrictly) {
return;
}
var activeNode = self.cascader.data.activeNode;
if (self.activeNodeId === nodeId) {
var ok = $li.find('.' + okIcon);
if (ok.length === 0) {
$li.prepend('<i class="' + fromIcon + ' ' + okIcon + ' el-cascader-node__prefix"></i>');
}
} else {
$li.find('.' + okIcon).remove();
}
if (activeNode && activeNode.path.some(function (node) {
return node.nodeId === nodeId;
})) {
$li.addClass('is-active');
$li.addClass('in-checked-path');
} else {
$li.removeClass('is-active');
$li.removeClass('in-checked-path');
}
},
/**
* 同步单选非关联样式
*/
syncRadioCheckStrictly: function (self) {
var $li = self.$li;
var checkStrictly = self.props.checkStrictly;
var multiple = self.props.multiple;
if (!$li || multiple || !checkStrictly) {
return;
}
var $radio = self.$radio;
var activeNode = self.cascader.data.activeNode;
var nodeId = self.nodeId;
if (self.activeNodeId === nodeId) {
$radio.find('.el-radio__input').addClass('is-checked');
} else {
$radio.find('.el-radio__input').removeClass('is-checked');
}
if (activeNode && activeNode.path.some(function (node) {
return node.nodeId === nodeId;
})) {
$li.addClass('is-active');
$li.addClass('in-checked-path');
} else {
$li.removeClass('is-active');
$li.removeClass('in-checked-path');
}
},
/**
* 同步多选关联样式
*/
syncMultiple: function (self) {
var $li = self.$li;
var checkStrictly = self.props.checkStrictly;
var multiple = self.props.multiple;
var disabledFixed = self.config.disabledFixed;
if (!multiple || checkStrictly) {
return;
}
var allLeafChildren = self.getAllLeafChildren(disabledFixed);
// 全部未选中 0
// 全部选中 1
// 部分选中 2
var checked = self._getMultipleChecked(allLeafChildren);
self._checked = checked;
if (!$li) {
return;
}
var $checkbox = self.$checked.find('.el-checkbox__input');
if (checked === 0) {
$checkbox.removeClass('is-checked');
$checkbox.removeClass('is-indeterminate');
} else if (checked === 1) {
$checkbox.removeClass('is-indeterminate');
$checkbox.addClass('is-checked');
} else if (checked === 2) {
$checkbox.removeClass('is-checked');
$checkbox.addClass('is-indeterminate');
}
},
/**
* 同步多选非关联样式
*/
syncMultipleCheckStrictly: function (self) {
var $li = self.$li;
var checkStrictly = self.props.checkStrictly;
var multiple = self.props.multiple;
if (!$li || !multiple || !checkStrictly) {
return;
}
var checkedNodes = self.cascader.data.checkedNodes;
var checkedNodeIds = self.checkedNodeIds;
var nodeId = self.nodeId;
var exist = checkedNodes.some(function (node) {
return node.path.some(function (node) {
return node.nodeId === nodeId;
});
});
var $checkbox = self.$checked.find('.el-checkbox__input');
if (checkedNodeIds.some(function (checkedNodeId) {
return checkedNodeId === nodeId;
})) {
// 选中
$checkbox.addClass('is-checked');
} else {
// 未选中
$checkbox.removeClass('is-checked');
}
if (exist) {
$li.addClass('in-checked-path');
} else {
$li.removeClass('in-checked-path');
}
}
},
/**
* 获取叶子节点value值
* @param disabled 是否包含禁用,默认不包含
* @returns {Node[]|*[]}
*/
getAllLeafChildren: function (disabled) {
var leaf = this.leaf;
if (leaf) {
return [this];
} else {
var leafs = [];
this.transferChildren(function (node) {
if (node.disabled && !disabled) {
return false;
}
node.leaf && leafs.push(node);
});
return leafs;
}
},
/**
* 展开当前节点
*/
expandPanel: function () {
var path = this.path;
var cascader = this.cascader;
path.forEach(function (node, index, array) {
if (index !== array.length - 1) {
var childrenNode = node.childrenNode;
cascader._appendMenu(childrenNode, node.level + 1, node.parentNode);
}
});
},
_getMultipleChecked: function (leafNodes) {
var cascader = this.cascader;
var checkedNodeIds = cascader.data.checkedNodeIds;
var allLeafIds = leafNodes.map(function (node) {
return node.nodeId;
});
// 全部未选中 0
// 全部选中 1
// 部分选中 2
var checked = 0;
for (var i = 0; i < allLeafIds.length; i++) {
var child = allLeafIds[i];
if (checked === 2) {
break;
}
if (checkedNodeIds.indexOf(child) !== -1) {
if (i > 0 && checked !== 1) {
checked = 2;
} else {
checked = 1;
}
} else {
// 当全部选中时,则改为部分选中,否则全部未选中
checked = checked === 1 ? 2 : 0;
}
}
return checked;
}
};
function Cascader(config) {
this.config = $.extend(true, {
elem: '', //绑定元素
value: null, //预设值
options: [], //可选项数据源,键名可通过 Props 属性配置
empty: '暂无数据', //无匹配选项时的内容
placeholder: '请选择',//输入框占位文本
disabled: false, //是否禁用
clearable: false, //是否支持清空选项
showAllLevels: true, //输入框中是否显示选中值的完整路径
collapseTags: false, //多选模式下是否折叠Tag
minCollapseTagsNumber: 1, //最小折叠标签数
separator: ' / ', //选项分隔符
filterable: false, //是否可搜索选项
filterMethod: function (node, keyword) {
return node.path.some(function (node) {
return node.label.indexOf(keyword) !== -1;
});
}, //自定义搜索逻辑第一个参数是节点node第二个参数是搜索关键词keyword通过返回布尔值表示是否命中
debounce: 300, //搜索关键词输入的去抖延迟,毫秒
beforeFilter: function (value) {
return true;
},//筛选之前的钩子,参数为输入的值,若返回 false,则停止筛选
popperClass: '', // 自定义浮层类名 string
extendClass: false, //继承class样式
extendStyle: false, //继承style样式
disabledFixed: false, //固定禁用项,使禁用项不被清理删除,禁用项只能通过函数添加或初始值添加,默认禁用项不可被函数或初始值添加
maxSize: 0, // 多选选中的最大数量0表示不限制
props: {
strictMode: false, //严格模式设置value严格按照层级结构.例如:[[1,2,3],[1,2,4]]
expandTrigger: 'click', //次级菜单的展开方式 string click / hover 'click'
multiple: false, //是否多选 boolean - false
checkStrictly: false, //是否严格的遵守父子节点不互相关联 boolean - false
lazy: false, //是否动态加载子节点,需与 lazyLoad 方法结合使用 boolean - false
lazyLoad: function (node, resolve) {
}, //加载动态数据的方法,仅在 lazy 为 true 时有效 function(node, resolve)node为当前点击的节点resolve为数据加载完成的回调(必须调用)
value: 'value', //指定选项的值为选项对象的某个属性值 string — 'value'
label: 'label', //指定选项标签为选项对象的某个属性值 string — 'label'
children: 'children', //指定选项的子选项为选项对象的某个属性值 string — 'children'
disabled: 'disabled', //指定选项的禁用为选项对象的某个属性值 string — 'disabled'
leaf: 'leaf' //指定选项的叶子节点的标志位为选项对象的某个属性值 string — 'leaf'
}
}, config);
this.data = {
nodeId: 1, //nodeId的自增值
nodes: [], //存储Node对象
menuData: [], //压入菜单的数据
activeNodeId: null, //存放NodeId
activeNode: null, //存放Node
checkedNodeIds: [], //存放多个NodeId
checkedNodes: [] //存放多个Node
};
// 面板是否展开
this.showPanel = false;
this.event = {
// 值变更事件
change: [],
// 打开事件
open: [],
// 关闭事件
close: []
}
// 是否正在搜索中
this.filtering = false;
// 初始化
this._init();
// 面板关闭事件id
this.closeEventId = 0;
// 是否进入maxSize模式
this._maxSizeMode = null;
}
Cascader.prototype = {
constructor: Cascader,
get props() {
return this.config.props;
},
get isFiltering() {
return this.filtering;
},
set isFiltering(filtering) {
if (this.filtering === filtering) {
return;
}
this.filtering = !!filtering;
var $panel = this.$panel;
if (this.filtering) {
$panel.find('.el-cascader-panel').hide();
$panel.find('.el-cascader__suggestion-panel').show();
} else {
$panel.find('.el-cascader-panel').show();
$panel.find('.el-cascader__suggestion-panel').hide();
this.$tagsInput && this.$tagsInput.val('')
}
},
set maxSizeMode(maxSizeMode) {
if (this._maxSizeMode !== maxSizeMode) {
this._maxSizeMode = maxSizeMode;
this.refreshMenu();
}
},
icons: {
from: 'layui-icon',
down: 'layui-icon-down',
close: 'layui-icon-close',
right: 'layui-icon-right',
ok: 'layui-icon-ok',
loading: 'layui-icon-loading-1 layui-anim layui-anim-rotate layui-anim-loop'
},
// 初始化
_init: function () {
this._checkConfig();
// 初始化输入框
this._initInput();
// 初始化面板
this._initPanel();
// 初始化选项值
this.setOptions(this.config.options);
var self = this;
// 监听滚动条
$(window).scroll(function () {
self._resetXY();
});
// 监听窗口
$(window).resize(function () {
self._resetXY();
});
// 点击事件,展开面板
this.$div.click(function (event) {
if (self.config.disabled) {
return;
}
var show = self.showPanel;
if (!show) {
self.open();
} else {
self.close();
}
});
},
/**
* 检查配置
* @private
*/
_checkConfig: function () {
var elem = this.config.elem;
if (!elem || $(elem).length === 0) {
throw new Error("缺少elem节点选择器");
}
var maxSize = this.config.maxSize;
if (typeof maxSize !== 'number' || maxSize < 0) {
throw new Error("maxSize应是一个大于等于0的有效的number值");
}
if (!Array.isArray(this.config.options)) {
throw new Error("options不是一个有效的数组");
}
},
/**
* 初始化根目录
* @private
*/
_initRoot: function () {
var lazy = this.props.lazy;
var lazyLoad = this.props.lazyLoad;
var self = this;
var nodes = this.data.nodes;
if (nodes.length > 0 || !lazy) {
this._appendMenu(nodes, 0);
} else if (lazy) {
this._appendMenu(nodes, 0);
lazyLoad({
root: true,
level: 0
}, function (nodes) {
self.data.nodes = self.initNodes(nodes, 0, null);
self._appendMenu(self.data.nodes, 0);
});
}
},
/**
* 设置选项值
* @param options
*/
setOptions: function (options) {
this.config.options = options;
// 初始化节点
this.data.nodes = this.initNodes(options, 0, null);
// 初始化根目录
this._initRoot();
// 初始化值
this.setValue(this.config.value);
},
// 面板定位
_resetXY: function () {
var $div = this.$div;
var offset = $div.offset();
var $panel = this.$panel;
if ($panel) {
var windowHeight = window.innerHeight;
var windowWidth = window.innerWidth;
var panelHeight = $panel.height();
var panelWidth = $panel.width();
var divHeight = $div.height();
var boundingClientRect = $div[0].getBoundingClientRect();
var $arrow = $panel.find('.popper__arrow');
// 距离右边界的偏差值
var offsetDiff = Math.min(windowWidth - boundingClientRect.x - panelWidth - 5, 0);
var bottomHeight = windowHeight - (boundingClientRect.top + divHeight);
if (bottomHeight < panelHeight && boundingClientRect.top > panelHeight + 20) {
$panel.attr('x-placement', 'top-start')
// 向上
$panel.css({
top: offset.top - 20 - panelHeight + 'px',
left: offset.left + offsetDiff + 'px'
});
} else {
$panel.attr('x-placement', 'bottom-start');
// 距离底部边界的偏差值
var yOffset = Math.max(panelHeight - (windowHeight - boundingClientRect.y - divHeight - 15), 0);
// 向下
$panel.css({
top: offset.top + divHeight - yOffset + 'px',
left: offset.left + offsetDiff + 'px'
});
}
// 箭头偏移
$arrow.css("left", 35 - offsetDiff + "px");
}
},
get $menus() {
return this.$panel && this.$panel.find('.el-cascader-panel .el-cascader-menu');
},
// 初始化输入框
_initInput: function () {
var $e = $(this.config.elem);
var self = this;
// 当绑定的元素带有value属性并且对象未设置值时设置一个初始值
if (this.config.value === null && $e.attr('value')) {
this.config.value = $e.attr('value');
}
var placeholder = this.config.placeholder;
var fromIcon = this.icons.from;
var downIcon = this.icons.down;
var multiple = this.props.multiple;
var extendClass = this.config.extendClass;
var extendStyle = this.config.extendStyle;
this.$div = $('<div class="el-cascader"></div>');
if (extendStyle) {
var style = $e.attr('style');
if (style) {
this.$div.attr('style', style);
}
}
if (extendClass) {
var className = $e.attr('class');
if (className) {
className.split(' ').forEach(function (name) {
self.$div.addClass(name);
});
}
}
this.$input = $('<div class="el-input el-input--suffix">' +
'<input type="text" readonly="readonly" autocomplete="off" placeholder="' + placeholder + '" class="el-input__inner">' +
'<span class="el-input__suffix">' +
'<span class="el-input__suffix-inner">' +
'<i class="el-icon-arrow-down ' + fromIcon + ' ' + downIcon + '" style="font-size: 12px"></i>' +
'</span></span>' +
'</div>')
this.$div.append(this.$input);
this.$inputRow = this.$input.find('.el-input__inner');
// 多选标签
if (multiple) {
this.$tags = $('<div class="el-cascader__tags"><!----></div>');
this.$div.append(this.$tags);
}
var element = this._initHideElement($e);
// 在后面插入元素
element.after(this.$div);
this.$icon = this.$input.find('i');
this._initFilterableInputEvent();
this.disabled(this.config.disabled);
},
/**
* 初始化隐藏元素input主要用于layui的表单验证
* @param $e
* @private
*/
_initHideElement: function ($e) {
var tagName = $e.prop("tagName").toLowerCase();
// 保存原始元素
if (tagName === 'input') {
$e.hide();
$e.attr('type', 'hidden')
this.$ec = $e;
return $e;
} else {
var attributes = $e[0].attributes;
var $input = $('<input />');
var keys = Object.keys(attributes);
for (var key in keys) {
var attribute = attributes[key];
$input.attr(attribute.name, attribute.value);
}
$input.hide();
$input.attr('type', 'hidden')
this.$ec = $input;
$e.before($input);
$e.remove();
return $input;
}
},
/**
* 初始化可搜索监听事件
* @private
*/
_initFilterableInputEvent: function () {
var filterable = this.config.filterable;
if (!filterable) {
return;
}
var timeoutID;
var multiple = this.props.multiple;
var debounce = this.config.debounce;
var placeholder = this.config.placeholder;
var beforeFilter = this.config.beforeFilter;
var filterMethod = this.config.filterMethod;
var checkStrictly = this.props.checkStrictly;
var self = this;
function filter(event) {
var input = this;
if (timeoutID) {
clearTimeout(timeoutID);
}
timeoutID = setTimeout(function () {
timeoutID = null;
var val = $(input).val();
if (!val) {
self.isFiltering = false;
return;
}
self.open();
if (typeof beforeFilter === 'function' && beforeFilter(val)) {
self.isFiltering = true;
var nodes = self.getNodes();
var filterNodes = nodes.filter(function (node) {
var disabled;
if (checkStrictly) {
disabled = node.disabled;
} else {
disabled = node.path.some(function (node) {
return node.disabled;
});
}
if ((node.leaf || checkStrictly) && !disabled) {
if (typeof filterMethod === 'function' && filterMethod(node, val)) {
// 命中
return true;
}
}
return false;
});
self._setSuggestionMenu(filterNodes);
}
}, debounce);
}
if (multiple) {
// 多选可搜索
this.$tagsInput = $('<input type="text" autocomplete="off" placeholder="' + placeholder + '" class="el-cascader__search-input">');
var $tagsInput = this.$tagsInput;
this.$tags.append($tagsInput);
$tagsInput.on('keydown', filter);
$tagsInput.click(function (event) {
if (self.isFiltering) {
stopPropagation(event);
}
});
} else {
var $inputRow = this.$inputRow;
// 单选可搜索
$inputRow.removeAttr('readonly');
$inputRow.on('keydown', filter);
$inputRow.click(function (event) {
if (self.isFiltering) {
stopPropagation(event);
}
});
}
},
// 初始化面板(panel(1))
_initPanel: function () {
var $panel = this.$panel;
var popperClass = this.config.popperClass || '';
if (!$panel) {
// z-index解决和layer.open默认19891016的冲突
this.$panel = $('<div class="el-popper el-cascader__dropdown ' + popperClass + '" style="position: absolute; z-index: 109891015;display: none;" x-placement="bottom-start"><div class="el-cascader-panel"></div><div class="popper__arrow" style="left: 35px;"></div></div>');
$panel = this.$panel;
$panel.appendTo('body');
$panel.click(function (event) {
// 阻止事件冒泡
stopPropagation(event);
});
// 初始化可搜索面板
this._initSuggestionPanel();
}
},
/**
* 添加菜单(panel(1)->menu(n))
* @param nodes 当前层级数据
* @param level 层级从0开始
* @param parentNode 父级节点
* @param _menuItem 刷新时传入的当前菜单的item数据
* @private
*/
_appendMenu: function (nodes, level, parentNode, _menuItem) {
this._removeMenu(level);
if (parentNode && parentNode.leaf) {
return;
}
var menuData = this.data.menuData;
var $div = $('<div class="el-scrollbar el-cascader-menu" role="menu" id="cascader-menu"><div class="el-cascader-menu__wrap el-scrollbar__wrap" style="margin-bottom: -17px; margin-right: -17px;"><ul class="el-scrollbar__view el-cascader-menu__list"></ul></div></div>');
// 重新添加菜单
this.$panel.find('.el-cascader-panel').append($div);
// 渲染细项
this._appendLi($div, nodes);
var menuItem = {nodes: nodes, level: level, parentNode: parentNode, scrollbar: {top: 0, left: 0}};
if (_menuItem) {
menuItem.scrollbar = _menuItem.scrollbar
}
// 渲染滚动条
this._initScrollbar($div, menuItem);
// 重新定位面板
this._resetXY();
menuData.push(menuItem);
},
/**
* 移除菜单
* @param level
* @private
*/
_removeMenu: function (level) {
// 除了上一层的所有菜单全部移除
var number = level - 1;
if (number !== -1) {
this.$panel.find('.el-cascader-panel .el-cascader-menu:gt(' + number + ')').remove();
} else {
this.$panel.find('.el-cascader-panel .el-cascader-menu').remove();
}
// 保存菜单数据
var menuData = this.data.menuData;
if (menuData.length > level) {
menuData.splice(level, menuData.length - level);
}
},
/**
* 添加细项(panel(1)->menu(n)->li(n))
* @param $menu 当前菜单对象
* @param nodes 当前层级数据
* @private
*/
_appendLi: function ($menu, nodes) {
var $list = $menu.find('.el-cascader-menu__list');
if (!nodes || nodes.length === 0) {
var isEmpty = this.config.empty;
$list.append('<div class="el-cascader-menu__empty-text">' + isEmpty + '</div>');
return;
}
$.each(nodes, function (index, node) {
node.bind($list);
});
},
/**
* 刷新菜单面板
*/
refreshMenu: function () {
// 先复制一个数组,避免刷新菜单时,数组的数据被改变
var data = this.data.menuData.concat([]);
var self = this;
data.forEach(function (data) {
self._appendMenu(data.nodes, data.level, data.parentNode, data);
})
},
/**
* 初始化可搜索面板
* @private
*/
_initSuggestionPanel: function () {
var filterable = this.config.filterable;
if (!filterable) {
return;
}
var $suggestionPanel = this.$suggestionPanel;
if (!$suggestionPanel) {
this.$suggestionPanel = $('<div class="el-cascader__suggestion-panel el-scrollbar" style="display: none;"><div class="el-scrollbar__wrap" style="margin-bottom: -17px; margin-right: -17px;"><ul class="el-scrollbar__view el-cascader__suggestion-list" style="min-width: 222px;"></ul></div></div>');
$suggestionPanel = this.$suggestionPanel;
this.$panel.find('.popper__arrow').before($suggestionPanel);
$suggestionPanel.click(function (event) {
// 阻止事件冒泡
stopPropagation(event);
});
}
},
/**
* 设置可搜索菜单
* @param nodes
* @private
*/
_setSuggestionMenu: function (nodes) {
var $suggestionPanel = this.$suggestionPanel;
var $list = $suggestionPanel.find('.el-cascader__suggestion-list');
$list.empty();
$suggestionPanel.find('.el-scrollbar__bar').remove();
if (!nodes || nodes.length === 0) {
$list.append('<li class="el-cascader__empty-text">无匹配数据</li>');
return;
}
$.each(nodes, function (index, node) {
node.bindSuggestion($list);
});
this._initScrollbar($suggestionPanel, {scrollbar: {top: 0, left: 0}});
this._resetXY();
},
/**
* 初始化节点数据
* @param data 原始数据
* @param level 层级
* @param parentNode 父级节点
* @returns {*[]}
*/
initNodes: function (data, level, parentNode) {
var nodes = [];
for (var key in data) {
var datum = data[key];
var node = new Node(datum, this, level, parentNode);
// 过滤value为null或者undefined的数据
if (node.value === null || node.value === undefined) {
continue;
}
nodes.push(node);
if (node.children && node.children.length > 0) {
node.setChildren(this.initNodes(node.children, level + 1, node));
}
}
return nodes;
},
/**
* 设置单选值
* @param nodeId 节点id
* @param node 节点对象
* @private
*/
_setActiveValue: function (nodeId, node) {
if (this.data.activeNodeId !== nodeId) {
var activeNode = this.data.activeNode;
this.data.activeNodeId = nodeId;
this.data.activeNode = node;
activeNode && activeNode.transferParent(function (node) {
node.syncStyle();
}, true);
node && node.transferParent(function (node) {
node.syncStyle();
}, true);
// 填充路径
this.change(node && node.value, node);
if (nodeId !== null) {
this._setClear();
}
}
},
/**
* 设置多选值
* @param nodeIds 值数组
* @param nodes 节点数组
* @private
*/
_setCheckedValue: function (nodeIds, nodes) {
var checkedNodes = this.data.checkedNodes;
var maxSize = this.config.maxSize;
var maxSizeMode;
if (nodeIds.length > 0 && maxSize !== 0 && nodeIds.length >= maxSize) {
nodeIds = nodeIds.slice(0, maxSize);
nodes = nodes.slice(0, maxSize);
maxSizeMode = true
} else {
maxSizeMode = false
}
this.data.checkedNodeIds = nodeIds || [];
this.data.checkedNodes = nodes || [];
var syncPath = [];
var syncNodeIds = [];
checkedNodes.forEach(function (node) {
node.path.forEach(function (node) {
if (syncNodeIds.indexOf(node.nodeId) === -1) {
syncPath.push(node);
syncNodeIds.push(node.nodeId);
}
});
});
nodes.forEach(function (node) {
node.path.forEach(function (node) {
if (syncNodeIds.indexOf(node.nodeId) === -1) {
syncPath.push(node);
syncNodeIds.push(node.nodeId);
}
});
});
syncPath.forEach(function (node) {
node.syncStyle();
});
// 填充路径
this.change(nodes.map(function (node) {
return node.value;
}), nodes);
this._setClear();
this.maxSizeMode = maxSizeMode;
},
/**
* 设置值
* @param value
*/
setValue: function (value) {
if (this.data.activeNodeId || this.data.checkedNodeIds.length > 0) {
// 清空值
this.clearCheckedNodes();
}
if (!value) {
return;
}
var strictMode = this.props.strictMode;
if (strictMode) {
if (!Array.isArray(value)) {
throw new Error("严格模式下,value必须是一个包含父子节点数组结构.");
}
}
var nodes = this.getNodes(this.data.nodes);
var checkStrictly = this.props.checkStrictly;
var multiple = this.props.multiple;
var disabledFixed = this.config.disabledFixed;
if (multiple) {
var paths = nodes.filter(function (node) {
if ((checkStrictly || node.leaf) && (!node.disabled || disabledFixed)) {
if (strictMode) {
// 严格模式下
// some:命中一个就为true
// every:全部命中为true
return value.some(function (levelValue) {
if (!Array.isArray(levelValue)) {
throw new Error("多选严格模式下,value必须是一个二维数组结构.");
}
var path = node.path;
return levelValue.length === path.length && levelValue.every(function (rowValue, index) {
return path[index].value === rowValue;
});
})
} else {
return value.indexOf(node.value) !== -1;
}
}
return false;
});
var nodeIds = paths.map(function (node) {
return node.nodeId;
});
this._setCheckedValue(nodeIds, paths);
// 展开第一个节点
if (paths.length > 0) {
var first = paths[0];
first.expandPanel();
}
} else {
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if ((checkStrictly || node.leaf)) {
var is = false;
if (strictMode) {
// 严格模式下
// every:全部命中为true
var path = node.path;
is = value.length === path.length && value.every(function (rowValue, index) {
return path[index].value === rowValue;
});
} else if (node.value === value) {
is = true;
}
if (is) {
this._setActiveValue(node.nodeId, node);
// 展开节点
node.expandPanel();
break;
}
}
}
}
},
/**
* 递归获取扁平的节点
* @param nodes
* @param container
* @returns {*[]}
*/
getNodes: function (nodes, container) {
if (!container) {
container = [];
}
if (!nodes) {
nodes = this.data.nodes;
}
var self = this;
nodes.forEach(function (node) {
container.push(node);
var children = node.getChildren();
if (children) {
self.getNodes(children, container);
}
});
return container;
},
/**
* 初始化滚动条
* @param $menu 菜单的dom节点对象
* @param menuItem 当前菜单数据
* @private
*/
_initScrollbar: function ($menu, menuItem) {
var $div = $('<div class="el-scrollbar__bar is-onhoriztal"><div class="el-scrollbar__thumb" style="transform: translateX(0%);"></div></div><div class="el-scrollbar__bar is-vertical"><div class="el-scrollbar__thumb" style="transform: translateY(0%);"></div></div>');
$menu.append($div);
var vertical = $($div[1]).find('.el-scrollbar__thumb');
var onhoriztal = $($div[0]).find('.el-scrollbar__thumb');
var scrollbar = $menu.find('.el-scrollbar__wrap');
var $panel = this.$panel;
var $lis = $menu.find('li');
var height = Math.max($panel.height(), $menu.height());
var hScale = (height - 6) / ($lis.height() * $lis.length);
var wScale = $panel.width() / $lis.width();
// 滚动条监听事件
function _scrollbarEvent(scrollTop, scrollLeft) {
if (hScale < 1) {
vertical.css('height', hScale * 100 + '%');
vertical.css('transform', 'translateY(' + scrollTop / $menu.height() * 100 + '%)');
}
if (wScale < 1) {
onhoriztal.css('width', wScale * 100 + '%');
onhoriztal.css('transform', 'translateY(' + scrollLeft / $menu.width() * 100 + '%)');
}
}
// 拖动事件
vertical.mousedown(function (event) {
event.stopImmediatePropagation();
stopPropagation(event);
// 禁止文本选择事件
var selectstart = function () {
return false;
};
$(document).bind("selectstart", selectstart);
var y = event.clientY;
var scrollTop = scrollbar.scrollTop();
// 移动事件
var mousemove = function (event) {
event.stopImmediatePropagation();
var number = scrollTop + (event.clientY - y) / hScale;
scrollbar.scrollTop(number);
};
$(document).bind('mousemove', mousemove);
// 鼠标松开事件
$(document).one('mouseup', function (event) {
stopPropagation(event);
event.stopImmediatePropagation();
$(document).off('mousemove', mousemove);
$(document).off('selectstart', selectstart);
});
});
// 监听滚动条事件
scrollbar.scroll(function () {
var scroll = $(this);
menuItem.scrollbar.top = scroll.scrollTop()
menuItem.scrollbar.left = scroll.scrollLeft()
_scrollbarEvent(menuItem.scrollbar.top, menuItem.scrollbar.left);
});
// 初始化滚动条
scrollbar.scrollTop(menuItem.scrollbar.top);
_scrollbarEvent(menuItem.scrollbar.top, menuItem.scrollbar.left);
},
// 填充路径
_fillingPath: function () {
var multiple = this.props.multiple;
var showAllLevels = this.config.showAllLevels;
var separator = this.config.separator;
var collapseTags = this.config.collapseTags;
var $inputRow = this.$inputRow;
var placeholder = this.config.placeholder;
var self = this;
if (!multiple) {
var activeNode = this.data.activeNode;
var path = activeNode && activeNode.path || [];
if (showAllLevels) {
this._$inputRowSetValue(path.map(function (node) {
return node.label;
}).join(separator));
} else {
this._$inputRowSetValue(activeNode && activeNode.label || "");
}
} else {
// 复选框
// 删除标签
this.$tags.find('.el-tag').remove();
var $tagsInput = this.$tagsInput;
// 清除高度
$inputRow.css('height', '');
var checkedNodes = this.data.checkedNodes;
var minCollapseTagsNumber = Math.max(this.config.minCollapseTagsNumber, 1);
if (checkedNodes.length > 0) {
var tags = [];
var paths = checkedNodes;
if (collapseTags) {
// 折叠tags
paths = checkedNodes.slice(0, Math.min(checkedNodes.length, minCollapseTagsNumber));
}
paths.forEach(function (node) {
tags.push(node.$tag);
});
// 判断标签是否折叠
if (collapseTags) {
// 判断标签最小折叠数
if (checkedNodes.length > minCollapseTagsNumber) {
tags.push(self.get$tag('+ ' + (checkedNodes.length - minCollapseTagsNumber), false));
}
}
tags.forEach(function (tag) {
if ($tagsInput) {
$tagsInput.before(tag)
} else {
self.$tags.append(tag);
}
});
}
var tagHeight = self.$tags.height();
var inputHeight = $inputRow.height();
if (tagHeight > inputHeight) {
$inputRow.css('height', tagHeight + 4 + 'px');
}
// 重新定位
this._resetXY();
if (checkedNodes.length > 0) {
$inputRow.removeAttr('placeholder');
$tagsInput && $tagsInput.removeAttr('placeholder', placeholder);
} else {
$inputRow.attr('placeholder', placeholder);
$tagsInput && $tagsInput.attr('placeholder', placeholder);
}
}
},
/**
* 设置单选输入框的值
* @param label
* @private
*/
_$inputRowSetValue: function (label) {
label = label || "";
var $inputRow = this.$inputRow;
$inputRow.attr('value', label); //防止被重置
$inputRow.val(label);
},
/**
* 获取复选框标签对象
* @param label
* @param showCloseIcon 是否显示关闭的icon
* @returns {jQuery|HTMLElement|*}
*/
get$tag: function (label, showCloseIcon) {
var fromIcon = this.icons.from;
var closeIcon = this.icons.close;
var icon = showCloseIcon ? '<i class="el-tag__close el-icon-close ' + fromIcon + ' ' + closeIcon + '"></i>' : '';
return $('<span class="el-tag el-tag--info el-tag--small el-tag--light"><span>' + label + '</span>' + icon + '</span>');
},
// 设置可清理
_setClear: function () {
var self = this;
function enter() {
self.$icon.removeClass(self.icons.down);
self.$icon.addClass(self.icons.close);
}
function out() {
self.$icon.removeClass(self.icons.close);
self.$icon.addClass(self.icons.down);
}
self.$div.mouseenter(function () {
enter();
});
self.$div.mouseleave(function () {
out();
});
self.$icon.off('click');
var multiple = this.props.multiple;
var clear;
if (multiple) {
clear = this.data.checkedNodeIds.length > 0;
} else {
clear = !!this.data.activeNodeId;
}
if (clear && !this.config.disabled && this.config.clearable) {
self.$icon.one('click', function (event) {
stopPropagation(event);
self.close();
self.clearCheckedNodes();
out();
self.$icon.off('mouseenter');
self.$div.off('mouseenter');
self.$div.off('mouseleave');
});
} else {
out();
self.$icon.off('mouseenter');
self.$div.off('mouseenter');
self.$div.off('mouseleave');
}
},
// 禁用
disabled: function (isDisabled) {
this.config.disabled = !!isDisabled;
if (this.config.disabled) {
this.$div.addClass('is-disabled');
this.$div.find('.el-input--suffix').addClass('is-disabled');
this.$inputRow.attr('disabled', 'disabled');
this.$tagsInput && this.$tagsInput.attr('disabled', 'disabled').hide()
} else {
this.$div.removeClass('is-disabled');
this.$div.find('.el-input--suffix').removeClass('is-disabled');
this.$inputRow.removeAttr('disabled');
this.$tagsInput && this.$tagsInput.removeAttr('disabled').show();
}
// 重新设置是否可被清理
this._setClear();
// 重新填充路径
this._fillingPath();
},
/**
* 当选中节点变化时触发 选中节点的值
* @param value 值
* @param node 节点
*/
change: function (value, node) {
var multiple = this.props.multiple;
if (multiple) {
if (value && value.length > 0) {
this.$ec.attr('value', JSON.stringify(value));
// this.$ec.val(JSON.stringify(value));
} else {
this.$ec.removeAttr('value');
// this.$ec.val('');
}
} else {
this.$ec.attr('value', value || "");
// this.$ec.val(value);
}
// 填充路径
this._fillingPath();
this.event.change.forEach(function (e) {
typeof e === 'function' && e(value, node)
})
},
/**
* 当失去焦点时触发 (event: Event)
* @param eventId 不为空时必须与closeEventId值相等防止旧事件触发
*/
close: function (eventId) {
if (this.showPanel && (!eventId || this.closeEventId === eventId)) {
this.showPanel = false;
this.$div.find('.layui-icon-down').removeClass('is-reverse');
this.$panel.slideUp(100);
this.visibleChange(false);
// 聚焦颜色
this.$input.removeClass('is-focus');
// 可搜索
var filterable = this.config.filterable;
if (filterable) {
this.isFiltering = false;
this._fillingPath();
}
this.event.close.forEach(function (e) {
typeof e === 'function' && e()
})
}
},
/**
* 当获得焦点时触发 (event: Event)
*/
open: function () {
if (!this.showPanel) {
this.showPanel = true;
this.closeEventId++;
var self = this;
// 当前传播事件结束后,添加点击背景关闭面板事件
setTimeout(function () {
$(document).one('click', self.close.bind(self, self.closeEventId));
});
// 重新定位面板
this._resetXY();
// 箭头icon翻转
this.$div.find('.layui-icon-down').addClass('is-reverse');
this.$panel.slideDown(200);
this.visibleChange(true);
// 聚焦颜色
this.$input.addClass('is-focus');
this.event.open.forEach(function (e) {
typeof e === 'function' && e()
})
}
},
/**
* 下拉框出现/隐藏时触发
* @param visible 出现则为 true隐藏则为 false
*/
visibleChange: function (visible) {
},
/**
* 在多选模式下移除Tag时触发 移除的Tag对应的节点的值
* @param tagValue 节点的值
* @param node 节点对象
*/
removeTag: function (tagValue, node) {
},
/**
* 获取选中的节点值
* @returns {null|[]}
*/
getCheckedValues: function () {
var strictMode = this.props.strictMode;
if (this.props.multiple) {
var checkedNodes = this.data.checkedNodes;
if (strictMode) {
return checkedNodes.map(function (node) {
return node.path.map(function (node1) {
return node1.value;
});
});
}
return checkedNodes.map(function (node) {
return node.value;
});
} else {
var activeNode = this.data.activeNode;
if (strictMode) {
return activeNode && activeNode.path.map(function (node) {
return node.value;
})
}
return activeNode && activeNode.value;
}
},
/**
* 获取选中的节点
* @returns {null|[]}
*/
getCheckedNodes: function () {
var strictMode = this.props.strictMode;
if (this.props.multiple) {
var checkedNodes = this.data.checkedNodes;
if (strictMode) {
return checkedNodes && checkedNodes.map(function (node) {
return node.path;
});
}
return checkedNodes;
} else {
var activeNode = this.data.activeNode;
if (strictMode) {
return activeNode && activeNode.path;
}
return activeNode;
}
},
/**
* 清空选中的节点
* @param force 强制清理禁用固定节点
*/
clearCheckedNodes: function (force) {
var multiple = this.props.multiple;
if (multiple) {
var disabledFixed = this.config.disabledFixed;
if (!force && disabledFixed) {
//禁用项被固定,则过滤出禁用项的选值出来
var checkedNodes = this.data.checkedNodes;
var disNodes = checkedNodes.filter(function (node) {
return node.disabled;
});
var nodeIds = disNodes.map(function (node) {
return node.nodeId;
});
this._setCheckedValue(nodeIds, disNodes);
} else {
this._setCheckedValue([], []);
}
} else {
this._setActiveValue(null, null);
}
}
};
var thisCas = function () {
var self = this;
return {
/**
* 设置选项值
* @param options
*/
setOptions: function (options) {
self.setOptions(options);
},
/**
* 覆盖当前值
* @param value 单选时传对象,多选时传数组
*/
setValue: function (value) {
self.setValue(value);
},
/**
* 当节点变更时,执行回调
* @param callback function(value,node){}
*/
changeEvent: function (callback) {
self.event.change.push(callback);
},
/**
* 当面板关闭时,执行回调
* @param callback function(){}
*/
closeEvent: function (callback) {
self.event.close.push(callback);
},
/**
* 当面板打开时,执行回调
* @param callback function(){}
*/
openEvent: function (callback) {
self.event.open.push(callback);
},
/**
* 禁用组件
* @param disabled true/false
*/
disabled: function (disabled) {
self.disabled(disabled);
},
/**
* 收起面板
*/
close: function () {
self.close();
},
/**
* 展开面板
*/
open: function () {
self.open();
},
/**
* 获取选中的节点如需获取路径使用node.path获取,将获取各级节点的node对象
* @returns {[]|*}
*/
getCheckedNodes: function () {
return self.getCheckedNodes();
},
/**
* 获取选中的值
* @returns {[]|*}
*/
getCheckedValues: function () {
return self.getCheckedValues();
},
/**
* 清空选中的节点
* @param force 强制清理禁用固定节点
*/
clearCheckedNodes: function (force) {
self.clearCheckedNodes(force);
},
/**
* 展开面板到节点所在的层级
* @param value 节点值,只能传单个值,不允许传数组
*/
expandNode: function (value) {
var nodes = self.getNodes(self.data.nodes);
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (node.value === value) {
node.expandPanel();
break;
}
}
},
/**
* 获取当前配置副本
*/
getConfig: function () {
return $.extend(true, {}, self.config);
},
/**
* 获取数据对象副本
* @returns {*}
*/
getData: function () {
return $.extend(true, {}, self.data);
}
};
};
exports('layCascader', function (option) {
var ins = new Cascader(option);
return thisCas.call(ins);
});
});