自定義下拉列表:
選中項左側標記、自定義滾動條樣式、上下鍵滾動列表,回撤確認、事件委託
效果圖:
代碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>select</title>
<style>
body {
background: #999999;
}
.baseSelect {
height: 30px;
width: 120px;
background-color: #252833;
color: rgba(255, 255, 255, 0.692);
font-size: 16px;
border-radius: 3px;
outline: none;
}
.baseSelect option {
display: none;
}
.selectPanel {
display: inline-block;
}
.selectPopupPanel {
position: absolute;
margin-left: 1px;
border-radius: 2px;
box-shadow: 1px 2px 10px 0 rgba(0, 0, 0, 0.5);
border: solid 1px rgba(213, 213, 213, 0.13);
background-color: #252833;
cursor: pointer;
outline: none;
display: none;
overflow: hidden;
}
.selectPopupPanel .scrollBar {
position: absolute;
top: 0;
right: 0;
width: 4px;
background-color: transparent;
}
.selectPopupPanel .scrollBar .slidBlock {
position: relative;
width: 100%;
border-radius: 2px;
background-color: #3d4351;
}
.selectOptions {
overflow-x: hidden;
overflow-y: scroll;
background-color: #252833;
margin-right: -100px;
}
.selectOptions .option {
width: 100%;
height: 42px;
background-color: transparent;
}
.selectOptions .option .tag {
float: left;
width: 4px;
height: 100%;
}
.selectOptions .option:hover, .selectOptions .optionSelected {
background-color: #343743;
}
.selectOptions .optionSelected .tag {
background-image: linear-gradient(5deg, #ff5858 15%, #f857a6 80%);
}
.selectOptions .option .optionText {
float: left;
line-height: 42px;
padding-left: 10px;
text-align: center;
font-family: Roboto;
font-size: 16px;
font-weight: normal;
font-stretch: normal;
font-style: normal;
letter-spacing: normal;
color: #b1b8c8;
user-select: none;
}
</style>
</head>
<body>
<div>item:</div>
<div class="selectPanel" style="margin-top: 200px;" id="s1">
<select class="baseSelect">
<option value="1">item1</option>
<option value="2">item2</option>
<option value="3">item3</option>
<option value="4">item4</option>
<option value="5">item5</option>
<option value="6">item6</option>
<option value="7">item7</option>
<option value="8">item8</option>
<option value="9">item9</option>
</select>
<div class="selectPopupPanel" tabindex="9999">
<div class="selectOptions"></div>
<div class="scrollBar">
<div class="slidBlock"></div>
</div>
</div>
</div>
<script>
function initSelect(value) {
let selectCompon = null;
if(typeof value == "string") {
selectCompon = document.getElementById(value);
} else {
selectCompon = value;
}
let select = selectCompon.getElementsByClassName("baseSelect")[0];
let selectPopupPanel = selectCompon.getElementsByClassName("selectPopupPanel")[0];
select.onclick = function () {
showSelectList(selectPopupPanel);
initSelectList(select, selectPopupPanel);
};
function getTop(e) {
var offset = e.offsetTop;
if (e.offsetParent != null) offset += getTop(e.offsetParent);
return offset;
}
function initSelectList(select, selectPopupPanel) {
let options = select.options;
let optionsCount = options.length;
if(optionsCount == 0) {
return;
}
let selectOptionsPanel = selectPopupPanel.getElementsByClassName("selectOptions")[0];
let divOptionsHtml = "";
for(let i=0; i<optionsCount; i++) {
divOptionsHtml +=
'<div data="'+options[i].value+'" class="option">' +
'<div class="tag"></div>' +
'<div class="optionText">'+options[i].text+'</div>' +
'</div>';
}
selectOptionsPanel.innerHTML = divOptionsHtml;
let scrollBar = selectPopupPanel.getElementsByClassName("scrollBar")[0]
let slidBlock = selectPopupPanel.getElementsByClassName("slidBlock")[0];
let divOptions = selectOptionsPanel.getElementsByClassName("option");
let scrollHeight = selectOptionsPanel.scrollHeight;
let panelHeight = scrollHeight;
let selectBottom = getTop(select) + select.clientHeight;
let windowHeight = window.innerHeight;
let marginTop = 0;
let showScrollBar = false;
let lastSelectedIndex = select.selectedIndex;
let selectedValue = function (index) {
selectOptionsPanel.scrollTop = selectOptionsPanel.scrollHeight * index / optionsCount;
divOptions[lastSelectedIndex].setAttribute("class", "option");
divOptions[index].setAttribute("class", "option optionSelected");
select.value = options[index].value;
lastSelectedIndex = index;
};
selectedValue(select.selectedIndex);
if (windowHeight - selectBottom < panelHeight) {
if (selectBottom - select.clientHeight > windowHeight / 2) {
let maxHeight = selectBottom - select.clientHeight - 50;
if (panelHeight > maxHeight) {
panelHeight = maxHeight;
showScrollBar = true;
}
marginTop = -panelHeight - select.clientHeight - 3;
} else {
panelHeight = windowHeight - selectBottom - 20;
showScrollBar = true;
}
}
selectPopupPanel.style.width = select.clientWidth - 2 + "px";
selectPopupPanel.style.marginTop = marginTop + "px";
selectOptionsPanel.style.maxHeight = panelHeight + "px";
selectPopupPanel.onblur = function() {
hideSelectList(selectPopupPanel);
}
let selectOptionsPanelTop = getTop(selectOptionsPanel);
selectOptionsPanel.onclick = function(e) {
let index = Math.floor(optionsCount * (e.clientY-selectOptionsPanelTop + selectOptionsPanel.scrollTop) / scrollHeight);
if(index >= optionsCount) {
index = optionsCount - 1;
}
changeSelectValue(options[index].value);
hideSelectList(selectPopupPanel);
}
if (showScrollBar) {
scrollBar.style.display = "block";
scrollBar.style.height = panelHeight + "px";
let scrollHandle = function () {
let scale = 1.0 * panelHeight / scrollHeight;
let scrollBarHeight = panelHeight * scale;
let scrollBarTop = selectOptionsPanel.scrollTop * scale;
slidBlock.style.marginTop = scrollBarTop + "px";
slidBlock.style.height = scrollBarHeight + "px";
};
selectOptionsPanel.scrollTop = 0;
selectOptionsPanel.onscroll = scrollHandle;
scrollHandle();
} else {
scrollBar.style.display = "none";
}
selectPopupPanel.onkeydown = function (event) {
let e = event || arguments.callee.caller.arguments[0];
if (!e) {
return;
}
let keyCode = e.keyCode;
if (keyCode != 38 && keyCode != 40 && keyCode != 13) {
return;
}
let lastTime = selectPopupPanel.lastTime || 0;
let nowTime = new Date().getTime();
if (nowTime - lastTime < 80) {
return;
}
selectPopupPanel.lastTime = nowTime;
let index = select.selectedIndex;
if (keyCode == 38) {
if (index > 0) {
selectedValue(--index);
}
} else if (keyCode == 40) {
if (index + 1 < optionsCount) {
selectedValue(++index);
}
} else if (keyCode == 13) {
changeSelectValue(options[index].value);
}
};
}
function hideSelectList(selectPopupPanel) {
if (selectPopupPanel.style.display == "none") {
return;
}
setTimeout(function () {
selectPopupPanel.style.display = "none";
}, 50);
}
function showSelectList(selectPopupPanel) {
if (selectPopupPanel.style.display == "block") {
return;
}
selectPopupPanel.style.display = "block";
selectPopupPanel.focus();
}
function changeSelectValue(value) {
select.value = value;
hideSelectList(selectPopupPanel);
select.dispatchEvent(new Event("change"));
}
}
initSelect("s1");
</script>
<script>
var s = document.getElementById("s1").getElementsByClassName("baseSelect")[0];
s.onchange = function(e) {
console.log("select:" + e.target.value);
}
</script>
</body>
</html>