JS實現多級下拉列表框
阿新 • • 發佈:2021-06-22
一、編寫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'); } }