一、編寫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');
}
}