1. 程式人生 > 其它 >JS實現多級下拉列表框

JS實現多級下拉列表框

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