一、编写HTML
<link type="text/css" rel="stylesheet" href="css/hm-multi-select.css" />
<script type="text/javascript" src="js/hm-multi-select.js"></script>
<script type="text/javascript" src="js/self-dynamic.js"></script>
<div id="hm-select-div"></div>
二、编写CSS
.disabled-div {
display : none;
}
#hm-select-div input {
width : 176px;
height: 30px;
border-radius: 3px;
float:left;
display:block;
padding:6px 12px;
font-size: 14px;
line-height: 1.42854143;
outline: 0;
border: 1px solid #e9e9e9;
}
#hm-select-div input:focus {
border-color: #66afe9;
outline: 0;
box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102,175,233,.6);
}
#hm-select-div{
display: inline-block;
}
.content-div {
margin-top:9px;
background: beige;
width : 176px;
z-index: 200;
position: absolute;
border: 1px solid #e9e9e9;
}
.content-div ul {
width: 176px;
margin:0 ;
padding:0;
}
.content-div ul li{
display: block;
font-size: 14px;
height:40px;
line-height: 40px;
list-style: none;
width: 168px;
padding-left:8px;
/*border-bottom: 1px solid #eee;*/
}
.content-div ul li:hover{
cursor: pointer;
color: #000;
background: cyan;
}
.choose-li{
background : #F5F7FA;
}
三、编写JS
模拟数据
// 设置数据源
let data = [{
id : 1,
type : 0,
name : ‘是非得失‘
},{
id : 1,
type : 0,
name : ‘塞翁失马‘
},{
id : 1,
type : 1,
name : ‘烦得很发过火‘
},{
id : 1,
type : 1,
name : ‘千万人就开了‘
},{
id : 1,
type : 1,
name : ‘第三方存在‘
},{
id : 1,
type : 1,
name : ‘和谐号占领太平洋‘
}];
window.onload = function() {
mainFloorInit(data);
}
// 下拉列表
window.addEventListener(‘li-hover-event‘, function(event) {
// 通过父级id取得子级data,并创建新的显示层
if(JSON.stringify(event.detail.type) === ‘1‘){
clearRedundantLi(event.detail.element);
return;
}
createNewDiv(data, event.detail.element);
});
效果文件
let floor = 1;
/**
* 删除多余的层级
* @param element li元素
*/
function clearRedundantLi(element) {
// 取得当前层级
let parentNode = element.parentNode.parentNode;
let currentFloor = Number(parentNode.getAttribute(‘floor‘));
// 删除多余的显示div
let outDiv = document.getElementById(‘hover-select‘);
let divArray = document.querySelectorAll(‘.content-div‘);
for(let divEle of divArray) {
let divFloor = divEle.getAttribute(‘floor‘);
if(divFloor>currentFloor){
outDiv.removeChild(divEle);
}
}
}
/**
* 创建多级select
* @param data
* @param element li元素
*/
function createNewDiv(data, element) {
// 取得当前层级
let parentNode = element.parentNode.parentNode;
let currentFloor = Number(parentNode.getAttribute(‘floor‘));
// 删除多余的显示div
clearRedundantLi(element);
let divELe = createSelectDiv(null, data);
// 设置新显示div的位置
divELe.style.position = ‘absolute‘;
divELe.style.left = (Number(parentNode.offsetLeft) + Number(parentNode.offsetWidth)) + ‘px‘;
divELe.style.top = parentNode.offsetTop + element.offsetTop + ‘px‘;
divELe.setAttribute(‘floor‘,String(currentFloor + 1));
}
/**
* 为input设置内容
* @param element 当前点击触发的li元素
*/
function setValue(element) {
// 为input设置内容
document.getElementById(‘selectText‘).value = element.innerHTML;
document.getElementById(‘selectText‘).setAttribute(‘val‘,element.value);
hideContainer();
let setValueEvent = new CustomEvent(‘select-set-value‘, {
detail : {
title : ‘set-value‘,
value : element.value,
text : element.innerHTML,
type : element.getAttribute(‘self-type‘)
}
});
window.dispatchEvent(setValueEvent);
}
/**
* 隐藏主图层
*/
function hideContainer() {
// 隐藏主图层
let outDiv = document.getElementById(‘hover-select‘);
outDiv.setAttribute(‘class‘,‘disabled-div‘);
// 清空多余的div
let divArray = document.querySelectorAll(‘.content-div‘);
for(let divEle of divArray) {
if(Number(divEle.getAttribute(‘floor‘))!==1){
outDiv.removeChild(divEle);
}
}
}
/**
* 初始化第一层
*/
function mainFloorInit(data){
let container = document.getElementById(‘hm-select-div‘);
// 创建input元素
let inputEle = document.createElement(‘input‘);
inputEle.setAttribute(‘id‘,‘selectText‘);
inputEle.setAttribute(‘type‘,‘text‘);
inputEle.setAttribute(‘placeholder‘,‘请选择相关部门‘);
container.appendChild(inputEle);
container.appendChild(document.createElement(‘br‘));
// 创建select层容器
let hoverDivELe = document.createElement(‘div‘);
hoverDivELe.setAttribute(‘id‘,‘hover-select‘);
// 隐藏select显示层
hoverDivELe.setAttribute(‘class‘,‘disabled-div‘);
// 新建一层
let firstFloorDivELe = createSelectDiv(hoverDivELe, data);
firstFloorDivELe.setAttribute(‘floor‘,‘1‘);
hoverDivELe.appendChild(firstFloorDivELe);
container.appendChild(hoverDivELe);
inputEle.onclick = function() {
let showClass = hoverDivELe.getAttribute(‘class‘);
if(showClass !== ‘disabled-div‘){
hoverDivELe.setAttribute(‘class‘,‘disabled-div‘);
hideContainer();
} else {
hoverDivELe.removeAttribute(‘class‘);
}
}
}
/**
* 创建一个新的select
* @param parentNode 父节点
* @param data 数据列表
* @returns {Element}
*/
function createSelectDiv(parentNode, data) {
if(parentNode == null){
parentNode = document.getElementById(‘hover-select‘);
}
// 新建一层
let divELe = document.createElement(‘div‘);
divELe.setAttribute(‘class‘,‘content-div‘);
// 新建ul
let ulEle = document.createElement(‘ul‘);
// 循环新建li
for(let item of data){
let liEle = document.createElement(‘li‘);
liEle.setAttribute(‘class‘,‘content-li‘);
liEle.innerHTML = item.name;
liEle.value = item.id;
liEle.setAttribute(‘self-type‘,item.type);
liEle.onclick = function() {
setValue(this);
};
liEle.onmouseenter = function() {
let liHoverEvent = new CustomEvent(‘li-hover-event‘, {
detail : {
title : ‘li-hove‘,
id : liEle.value,
type : item.type,
element : liEle
}
});
// 触发事件,创建新显示层
window.dispatchEvent(liHoverEvent);
};
liEle.onmouseout = function(event) {
let floorDiv = liEle.parentNode.parentNode;
clearLiClass(floorDiv);
// 取得当前坐标
let x = event.clientX;
let y = event.clientY;
// 父级div坐标
let left = floorDiv.offsetLeft;
let top = floorDiv.offsetTop;
let right = floorDiv.offsetLeft + floorDiv.offsetWidth;
let bottom = floorDiv.offsetTop + floorDiv.offsetHeight;
// 判断鼠标是否离开div
if( x < left || x > right || y < top || y > bottom){
liEle.setAttribute(‘class‘,‘content-li choose-li‘);
}
};
ulEle.appendChild(liEle);
}
divELe.appendChild(ulEle);
divELe.onmouseenter = function(event) {
let floorDiv = event.target;
clearLiClass(floorDiv);
}
parentNode.appendChild(divELe);
return divELe;
}
function clearLiClass(element) {
let liElements = element.childNodes[0].childNodes;
for(let liEle of liElements) {
liEle.setAttribute(‘class‘,‘content-li‘);
}
}