/**
* 级联选择器模块
* date:2019-07-27 License By http://easyweb.vip
*/
layui.define(function (exports) {
var $ = layui.jquery;
layui.link(layui.cache.base + 'cascader/cascader.css');
var onVisibleChangeList = []; // 所有展开和关闭回调
var cascader = {
/* 初始化 */
render: function (param) {
// 默认参数
var defaultOptions = {
renderFormat: function (labels, values) {
return labels.join(' / ');
},
clearable: true,
clearAllActive: false,
disabled: false,
trigger: 'click',
changeOnSelect: false,
filterable: false,
notFoundText: '没有匹配数据'
};
param = $.extend(defaultOptions, param);
var elem = param.elem; // 目标元素
var mDataList = param.data; // 数据
var renderFormat = param.renderFormat; // 选择后用于展示的函数
var clearable = param.clearable; // 是否支持清除
var clearAllActive = param.clearAllActive; // 清除所有选中
var disabled = param.disabled; // 是否禁用
var trigger = param.trigger; // 次级菜单触发方式
var changeOnSelect = param.changeOnSelect; // 是否点击每项选项值都改变
var reqData = param.reqData; // 自定义获取数据的方法
var filterable = param.filterable; // 是否开启搜索
var notFoundText = param.notFoundText; // 搜索列表为空时显示的内容
var reqSearch = param.reqSearch; // 自定义搜索的方法
var onChange = param.onChange; // 数据选择完成的回调
var onVisibleChange = param.onVisibleChange; // 展开和关闭弹窗时触发
var itemHeight = param.itemHeight; // 下拉列表每一项高度
var isFirst = true;
// 如果渲染过重新渲染
var $elem = $(elem);
if ($elem.next().hasClass('ew-cascader-group')) {
$elem.next().remove();
for (var i = 0; i < onVisibleChangeList.length; i++) {
if (elem == onVisibleChangeList[i].elem) {
onVisibleChangeList.splice(i, 1);
break;
}
}
}
onVisibleChangeList.push({elem: elem, onVisibleChange: onVisibleChange});
$elem.addClass('ew-cascader-hide');
var htmlStr = '
';
htmlStr += '
';
htmlStr += ' ';
htmlStr += ' ';
htmlStr += ' ';
htmlStr += ' ';
htmlStr += ' ';
htmlStr += '
';
htmlStr += '
';
htmlStr += '
';
htmlStr += '
';
$elem.after(htmlStr);
var $cascader = $elem.next();
var $inputGroup = $cascader.children('.ew-cascader-input-group');
var $input = $inputGroup.children('.ew-cascader-input');
var $inputSearch = $inputGroup.children('.ew-cascader-input-search');
var $dropdown = $cascader.children('.ew-cascader-dropdown');
var $search = $cascader.children('.ew-cascader-search-list');
$input.attr('placeholder', $elem.attr('placeholder'));
disabled && $input.addClass('layui-disabled');
// 构建渲染后的实例
var _instance = {
data: mDataList,
/* 展开 */
open: function () {
if ($cascader.hasClass('ew-cascader-open')) {
return;
}
cascader.hideAll();
$cascader.addClass('ew-cascader-open');
cascader.checkWidthPosition($dropdown); // 溢出屏幕判断
cascader.checkHeightPosition($dropdown); // 溢出屏幕判断
onVisibleChange && onVisibleChange(true); // 展开回调
if (filterable) { // 如果开启搜索功能让输入框获取焦点
$inputGroup.addClass('show-search');
$inputSearch.focus();
}
},
/* 关闭 */
hide: function () {
if (!$cascader.hasClass('ew-cascader-open')) {
return;
}
$cascader.removeClass('ew-cascader-open');
$cascader.removeClass('dropdown-show-top');
$cascader.removeClass('dropdown-show-left');
cascader.hideAllSearch();
onVisibleChange && onVisibleChange(false); // 关闭回调
},
/* 移除加载中的状态*/
removeLoading: function () {
$cascader.removeClass('show-loading');
$dropdown.find('.ew-cascader-dropdown-list-item').removeClass('show-loading');
},
/* 设置禁用状态 */
setDisabled: function (dis) {
disabled = dis;
if (dis) {
$input.addClass('layui-disabled');
_instance.hide();
} else {
$input.removeClass('layui-disabled');
}
},
/* 获取值*/
getValue: function () {
return $elem.val();
},
/* 获取label */
getLabel: function () {
return $input.val();
},
/* 设置值*/
setValue: function (value) {
if (value == undefined || value == null || !value.toString()) {
$input.val('');
$elem.val('');
if (clearAllActive || changeOnSelect) { // 清除所有
$dropdown.children('.ew-cascader-dropdown-list').not(':first').remove();
$dropdown.find('.ew-cascader-dropdown-list-item').removeClass('active');
cascader.checkWidthPosition($dropdown); // 溢出屏幕判断
} else { // 仅清除最后一项
$dropdown.find('.ew-cascader-dropdown-list-item.is-last').removeClass('active');
}
$inputGroup.removeClass('show-clear');
return;
}
value = value.toString().split(',');
var labels = [];
// 通过递归控制异步加载回显默认值对应label时的请求顺序
function doReqData(tValues, data, i, values, callback) {
if (!tValues && data) {
tValues = [];
setData(data);
} else if (tValues && data && data.children) {
setData(data.children);
} else { // 数据不存在时才去请求数据
$cascader.addClass('show-loading');
reqData(tValues, function (dataList) {
if (tValues) {
data.children = dataList;
} else {
mDataList = dataList;
tValues = [];
}
setData(dataList);
}, data);
}
function setData(dataList) {
for (var j = 0; j < dataList.length; j++) {
if (dataList[j].value == values[i]) {
labels[i] = dataList[j].label;
tValues[i] = dataList[j].value;
if (i < values.length - 1) {
doReqData(tValues, dataList[j], i + 1, values, callback);
} else {
callback();
}
break;
}
}
}
}
doReqData(undefined, mDataList, 0, value, function () {
$cascader.removeClass('show-loading');
$input.val(renderFormat(labels, value));
$elem.val(value.join(','));
});
}
};
// 回显初始值
_instance.setValue($elem.val());
// 点击展开/关闭下拉列表
$inputGroup.off('click').on('click', function (e) {
// 判断是否是禁用状态
if ($input.hasClass('layui-disabled')) {
return;
}
// 判断是否是加载中状态
if ($cascader.hasClass('show-loading')) {
return;
}
// 关闭
if ($cascader.hasClass('ew-cascader-open')) {
if (!filterable) { // 是否开启搜索功能
_instance.hide();
}
return;
}
// 展开
if (isFirst) { // 第一次展开渲染第一列数据
if (mDataList) {
isFirst = false;
renderList($dropdown, mDataList, undefined, itemHeight);
initLabel();
_instance.open();
} else { // 异步方式
$cascader.addClass('show-loading');
reqData(undefined, function (dataList) {
isFirst = false;
mDataList = dataList;
renderList($dropdown, dataList, undefined, itemHeight);
$cascader.removeClass('show-loading');
_instance.open();
}, undefined);
}
} else {
initLabel();
_instance.open();
}
// 回显上次选中项
function initLabel() {
var value = $elem.val().toString();
if (value) {
value = value.split(',');
for (var i = 0; i < value.length; i++) {
var $item = $dropdown.children('.ew-cascader-dropdown-list').eq(i).children('.ew-cascader-dropdown-list-item[data-value="' + value[i] + '"]');
if (i == value.length - 1) {
$item.addClass('active');
} else {
$item.trigger('click');
}
}
} else {
_instance.setValue();
}
}
});
$inputGroup.children('.ew-icon-arrow').off('click').on('click', function (e) {
if ($cascader.hasClass('ew-cascader-open')) {
_instance.hide();
e.stopPropagation();
}
});
// 点击渲染次级列表
$dropdown.off('click').on('click', '.ew-cascader-dropdown-list-item', function () {
var $this = $(this);
// 防止重复点击
if ($this.hasClass('active')) {
if ($this.hasClass('is-last')) {
_instance.hide();
}
return;
}
// 判断是否是禁用状态
if ($this.hasClass('ew-cascader-disabled')) {
return;
}
// 判断是否是加载中状态
if ($this.parent().parent().find('.ew-cascader-dropdown-list-item').hasClass('show-loading')) {
return;
}
var index = $this.data('index').toString();
var indexList = index.split('-');
var data = mDataList[parseInt(indexList[0])], values = [data.value], labels = [data.label];
for (var i = 1; i < indexList.length; i++) {
data = data.children[parseInt(indexList[i])];
values[i] = data.value;
labels[i] = data.label;
}
if (data.haveChildren) { // 非最后一项
if (data.children) { // 数据方式或已经异步加载直接渲染
$this.parent().nextAll().remove();
cascader.checkWidthPosition($dropdown); // 检查是否溢出屏幕
activeThis();
renderList($dropdown, data.children, index, itemHeight);
} else { // 异步方式先请求数据再渲染
$this.addClass('show-loading');
reqData(values, function (dataList) {
data.children = dataList;
$this.parent().nextAll().remove();
cascader.checkWidthPosition($dropdown); // 检查是否溢出屏幕
activeThis();
renderList($dropdown, dataList, index, itemHeight);
$this.removeClass('show-loading');
}, data);
}
// 点击非最后一项也触发选中
if (changeOnSelect) {
activeThis();
doChange();
}
} else { // 最后一项
$this.parent().nextAll().remove();
activeThis();
doChange();
_instance.hide(); // 选中后关闭
}
/* 选中当前 */
function activeThis() {
$this.parent().children('.ew-cascader-dropdown-list-item').removeClass('active');
$this.addClass('active');
}
/* 触发选中回调 */
function doChange() {
$input.val(renderFormat(labels, values)); // 赋值label
$elem.val(values.join(',')); // 赋值value
$elem.removeClass('layui-form-danger'); // 移除表单验证
onChange && onChange(values, data); // 选中回调
}
});
// hover方式触发
if (trigger == 'hover') {
$dropdown.off('mouseenter').on('mouseenter', '.ew-cascader-dropdown-list-item', function () {
if (!$(this).hasClass('is-last')) {
$(this).trigger('click');
}
});
}
// 开启清除功能
if (clearable) {
$inputGroup.off('mouseenter').on('mouseenter', function () {
if ($elem.val().toString()) {
$(this).addClass('show-clear');
}
});
$inputGroup.off('mouseleave').on('mouseleave', function () {
$(this).removeClass('show-clear');
});
// 点击清除
$inputGroup.children('.ew-icon-clear').off('click').on('click', function (e) {
e.stopPropagation();
_instance.setValue();
});
}
// 开启搜索功能
if (filterable) {
$inputSearch.off('input').on('input', function () {
var value = $(this).val();
if (!value) {
$cascader.removeClass('show-search-list');
$inputGroup.removeClass('have-value');
return;
}
$inputGroup.addClass('have-value');
if (reqSearch) { // 异步搜索
reqSearch(value, function (rsList) {
// 渲染搜索结果
renderSearchList($search, rsList, notFoundText);
$cascader.addClass('show-search-list');
}, mDataList);
} else { // 前端搜索
var allList = [], rsList = [];
// 把树形list转一维list
function toAllList(arr, label, value, disabled) {
for (var i = 0; i < arr.length; i++) {
var item = arr[i];
item.__label = label ? label + ' / ' + item.label : item.label;
item.__value = value ? value + ',' + item.value : item.value;
item.__disabled = item.disabled ? item.disabled : disabled;
if (item.children && item.children.length) {
toAllList(item.children, item.__label, item.__value, item.__disabled);
delete item.__label;
delete item.__value;
} else {
allList.push({
label: item.__label,
value: item.__value,
disabled: item.__disabled
});
}
}
}
toAllList(mDataList);
// 过滤数据
for (var i = 0; i < allList.length; i++) {
var item = allList[i];
if (item.label.indexOf(value) > -1) {
item.label = item.label.replace(new RegExp(value, 'g'), '' + value + '');
rsList.push(item);
}
}
// 渲染搜索结果
renderSearchList($search, rsList, notFoundText);
$cascader.addClass('show-search-list');
}
});
$search.off('click').on('click', '.ew-cascader-search-list-item', function (e) {
e.stopPropagation();
if ($(this).hasClass('ew-cascader-disabled')) { // 是否禁用
return;
}
_instance.hide();
_instance.setValue($(this).data('value'));
});
}
return _instance;
},
/** 关闭所有 */
hideAll: function () {
cascader.hideAllSearch();
for (var i = 0; i < onVisibleChangeList.length; i++) {
var elem = onVisibleChangeList[i].elem;
var onVisibleChange = onVisibleChangeList[i].onVisibleChange;
var $cascader = $(elem).next();
if ($cascader.hasClass('ew-cascader-open')) {
$cascader.removeClass('ew-cascader-open');
$cascader.removeClass('dropdown-show-top');
$cascader.removeClass('dropdown-show-left');
onVisibleChange && onVisibleChange(false);
}
}
},
/** 关闭所有搜索面板 */
hideAllSearch: function () {
$('.ew-cascader-input-group').removeClass('show-search');
$('.ew-cascader-group').removeClass('show-search-list');
$('.ew-cascader-input-group').removeClass('have-value');
$('.ew-cascader-input-search').val('');
},
/* 获取浏览器高度 */
getPageHeight: function () {
return document.documentElement.clientHeight || document.body.clientHeight;
},
/* 获取浏览器宽度 */
getPageWidth: function () {
return document.documentElement.clientWidth || document.body.clientWidth;
},
/* 检查宽度是否溢出屏幕 */
checkWidthPosition: function ($dropdown) {
if ($dropdown.offset().left + $dropdown.outerWidth() > cascader.getPageWidth()) {
$dropdown.parent().addClass('dropdown-show-left');
} else {
$dropdown.parent().removeClass('dropdown-show-left');
}
},
/* 检查高度是否溢出屏幕 */
checkHeightPosition: function ($dropdown) {
if ($dropdown.offset().top + $dropdown.outerHeight() > cascader.getPageHeight()) {
$dropdown.parent().addClass('dropdown-show-top');
if ($dropdown.offset().top < 0) {
$dropdown.parent().removeClass('dropdown-show-top');
}
}
}
};
/** 渲染列表 */
var renderList = function ($dropdown, dataList, pIndex, itemHeight) {
var style = itemHeight ? ' style="height:' + itemHeight + ';"' : '';
var htmlStr = '';
for (var i = 0; i < dataList.length; i++) {
var item = dataList[i];
var index = pIndex == undefined ? i : (pIndex + '-' + i);
if (item.haveChildren == undefined) {
item.haveChildren = item.children ? true : false;
}
var className = item.haveChildren ? '' : ' is-last'; // 是否是叶子节点
item.disabled && (className += ' ew-cascader-disabled'); // 是否禁用
htmlStr += '
' + item.label + '
';
}
htmlStr += '
';
$dropdown.append(htmlStr);
cascader.checkWidthPosition($dropdown); // 检查是否溢出屏幕
};
/** 渲染搜索列表 */
var renderSearchList = function ($search, dataList, notFoundText) {
var htmlStr = '';
if (dataList.length == 0) {
htmlStr = '' + notFoundText + '
';
} else {
for (var i = 0; i < dataList.length; i++) {
var item = dataList[i];
var className = item.disabled ? ' ew-cascader-disabled' : ''; // 是否禁用
htmlStr += '' + item.label + '
';
}
}
$search.html(htmlStr);
};
// 点击空白区域关闭下拉列表
$(document).off('click.cascader').on('click.cascader', function (e) {
try {
var classNames = e.target.className.split(' ');
var cascaders = ['ew-cascader-group', 'ew-cascader-input', 'ew-icon-arrow', 'ew-cascader-dropdown', 'ew-cascader-dropdown-list', 'ew-cascader-dropdown-list-item', 'ew-icon-right', 'ew-cascader-input-search', 'ew-cascader-search-list', 'ew-cascader-search-list-item'];
for (var i in classNames) {
for (var j in cascaders) {
if (classNames[i] == cascaders[j]) {
return;
}
}
}
} catch (e) {
}
cascader.hideAll();
});
exports('cascader', cascader);
});