组件特点
- jq环境
- 封装可复用
- 使用简单
代码
赶任务,bug后面慢慢修复,没做联动数量限制。
更新: 修复了大部分可见的bug,已在项目中使用。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
.jq-cascader {
display: inline-block;
border: 1px solid #ccc;
cursor: pointer;
position: relative;
width: 200px;
height: 26px;
line-height: 26px;
padding: 0 5px;
box-sizing: border-box;
font-size: 12px;
background-color: #fff;
}
.jq-cascader * {
box-sizing: border-box;
}
.jq-cascader .body .value {
color: #666;
}
.jq-cascader .body .arrow {
border-top: 2px solid #333;
border-right: 2px solid #333;
width: 6px;
height: 6px;
display: inline-block;
position: absolute;
right: 10px;
top: 9px;
transform: rotate(135deg);
transform-origin: center;
transition: 0.2s;
}
.jq-cascader .dropdown-content {
position: absolute;
left: -1px;
top: 26px;
display: flex;
z-index: 100;
height: 0px;
overflow: hidden;
}
.jq-cascader .dropdown-content.show {
height: 150px;
}
.jq-cascader .dropdown-content>.box {
width: 100px;
height: 150px;
border: 1px solid #ccc;
border-left: 0;
overflow: auto;
padding: 1px;
background-color: #fff;
}
.jq-cascader .dropdown-content>.box:first-child {
width: 100px;
height: 150px;
border-left: 1px solid #ccc;
}
.jq-cascader .dropdown-content>.box.no-data {
width: 200px;
height: 100px;
background-color: #fff;
text-align: center;
color: #999;
font-size: 12px;
}
.jq-cascader .dropdown-content>.box>.item {
height: 26px;
line-height: 26px;
padding: 0 5px;
display: flex;
justify-dropdown-content: space-between;
position: relative;
background-color: #fff;
}
.jq-cascader .dropdown-content>.box>.item:hover,
.jq-cascader .dropdown-content>.box>.item.active {
background-color: #ccc;
color: #fff;
}
.jq-cascader .dropdown-content>.box>.item>.arrow {
border-top: 1px solid #333;
border-right: 1px solid #333;
width: 5px;
height: 5px;
display: inline-block;
position: absolute;
right: 10px;
top: 10px;
transform: rotate(45deg);
}
.jq-cascader .dropdown-content>.box>.item>span {
width: 80%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
</head>
<body>
<div>
<div class="jq-cascader" id="myCascader"></div>
<div class="jq-cascader" id="myCascader2"></div>
</div>
<script src="jquery-1.12.4.min.js"></script>
<script>
/**
* 联动选择器
* @param {string} id
* @param {[{label: string; value: string; children: []}]} sourceData
* @param {boolean} selectRoot - 是否必需选择根节点, 默认 false
*/
var JQCascader = function (id, sourceData, selectRoot) {
this.id = id;
this.cascader = $('#' + this.id);
this.body = null;
this.content = null;
this.html = '';
this.uid = '';
this.label = '';
this.label = '';
this.selectRoot = selectRoot || false;
console.log(this.selectRoot);
this.sourceData = sourceData || [];
this.init();
};
// 原型方法
JQCascader.prototype = {
init: function () {
var that = this;
this.initContainer();
this.initData(this.sourceData);
this.setChecked();
this.body.click(function (e) {
that.show();
});
this.body.find('.clear').click(function (e) {
that.clear();
});
this.content.on('click', '.item', function () {
that.uid = $(this).attr('data-uid');
that.setChecked();
});
$(document).on('click', function (event) {
if ($(event.target).attr('data-tag') !== that.id) {
that.hide();
}
});
},
// 渲染下拉部分
renderHTML: function () {
var that = this;
this.html = '';
if (this.sourceData.length === 0) {
return;
}
if (this.uid !== '') {
var uids = this.uid.split('-');
var source = this.sourceData;
addHtml(this.sourceData);
uids.forEach(function (idx, index) {
source = source[idx].children;
if (source && source.length > 0) {
addHtml(source);
}
});
} else {
addHtml(this.sourceData);
}
this.content.html($(this.html));
function addHtml(data) {
that.html += '<div class="box" data-tag="' + that.id + '">';
data.forEach(function (item) {
that.html += `<div class="item ${item.checked ? 'active' : ''}" data-uid="${item.uid}" data-value="${
item.value
}" data-tag="${that.id}">
<span class="value" data-tag="${that.id}">${item.label}</span>
<i class="${item.children && item.children.length > 0 ? 'arrow' : ''}" data-tag="${that.id}">
</i>
</div>`;
});
that.html += '</div>';
}
},
// 初始化数据
initData: function (data, uid) {
var that = this;
data.forEach(function (item, index) {
item.checked = false;
item.uid = uid ? uid + '-' + index : index + '';
if (item.children && item.children.length > 0) {
that.initData(item.children, item.uid);
}
});
},
// 计算嵌套深度
getDeep: function () {
var deepArr = [];
deep(this.sourceData, 0, deepArr);
function deep(data, i, deepArr) {
i += 1;
for (let j = 0; j < data.length; j++) {
if (data[j].children) {
deep(data[j].children, i, deepArr);
} else {
return deepArr.push(i);
}
}
}
return deepArr;
},
// 重置数据的checked状态
resetChecked: function (data) {
var that = this;
data.forEach(function (item, index) {
item.checked = false;
if (item.children && item.children.length > 0) {
that.resetChecked(item.children);
}
});
},
// 设置checked状态
setChecked: function () {
var that = this;
var uids = this.uid.split('-');
this.resetChecked(this.sourceData);
var source = this.sourceData;
var label = '';
var value = [];
uids.forEach(function (idx, index) {
if (idx === '') {
return;
}
source[idx].checked = true;
label += index === 0 ? source[idx].label : '/' + source[idx].label;
value.push(source[idx].value);
source = source[idx].children;
// 未到根节点也执行选中
if (!that.selectRoot) {
that.value = value;
that.body.find('.value').text(label);
}
// 当当前选项到底时,结束分层点击
if (!source) {
that.hide();
that.value = value;
that.body.find('.value').text(label);
}
});
this.renderHTML();
},
hide: function () {
this.content.removeClass('show');
},
show: function () {
this.content.addClass('show');
},
getValue: function () {
return this.value;
},
// 回显数据
setUid: function (uid) {
this.uid = uid;
this.setChecked();
},
// 设置数据
setData: function (data) {
this.sourceData = data;
this.initData(this.sourceData);
this.setChecked();
},
// 清空
clear: function () {
this.uid = '';
this.value = [];
this.setChecked();
this.body.find('.value').text('please select');
},
// 初始化容器
initContainer: function () {
var html = `
<div class="body" data-tag="${this.id}">
<div class="value" data-tag="${this.id}">please select</div>
<span class="clear" >x</span>
<span class="arrow" data-tag="${this.id}"></span>
</div>
<div class="dropdown-content" data-tag="${this.id}">
<div class="box no-data" data-tag="' + that.id + '">
No Data !
</div>
</div>
`;
this.cascader.html(html);
this.body = this.cascader.find('.body');
this.content = this.cascader.find('.dropdown-content');
},
};
var data = [
{
label: "0",
value: "0",
children: [
{
label: "0-0",
value: "0-0",
children: [
{
label: "0-0-0",
value: "0-0-0",
children: [
{
label: "0-0-0-0",
value: "0-0-0-0",
},
{
label: "0-0-0-1",
value: "0-0-0-1",
},
]
},
{
label: "0-0-0",
value: "0-0-0",
},
]
},
]
},
{
label: "0",
value: "0",
children: [
{
label: "0-0",
value: "0-0",
children: [
{
label: "0-0-0",
value: "0-0-0",
children: [
{
label: "0-0-0-0",
value: "0-0-0-0",
},
{
label: "0-0-0-1",
value: "0-0-0-1",
},
]
},
]
},
]
},
];
var myCascader = new JQCascader("myCascader", data);
new JQCascader("myCascader2", data);
myCascader.setUid("0-0-0-1");
</script>
</body>
</html>