带搜索的下拉组件
最近遇到的这种需求比较多,直接花点时间封装了一个:
- 完全原生JS,不依赖框架
- css、html分离,更方便修改
- 自适应列表项的长度
css样式,可以根据实际需求进行修改
.moreselect{
width: 200px;
margin-top: 200px;
margin-left: 50px;
position: relative;
}
.moreselect_show{
height: 20px;
border: 1px solid #ccc;
border-top-color: #666;
border-left-color: #666;
position: relative;
line-height: 20px;
font-size: 14px;
padding-left: 5px;
padding-right: 20px;
}
.moreselect_show_in{
display: flex;
overflow: hidden;
white-space: nowrap;
container-type: inline-size;
}
.moreselect_show p{
white-space: nowrap;
}
.moreselect_show p:hover{
animation: marquee 3s linear infinite both alternate;
}
@keyframes marquee {
to {
transform: translateX(min(100cqw - 100%, 0px));
}
}
.moreselect_show::after{
content: "";
width: 5px;
height: 5px;
border-left: 2px solid #333;
border-bottom: 2px solid #333;
position: absolute;
right: 6px;
top: 50%;
transform: translateY(-50%) rotate(135deg);
}
.moreselect_show:has(+ .noshow)::after{
transform: translateY(-50%) rotate(315deg);
}
.moreselect_list{
width: 100%;
padding: 5%;
position: absolute;
top: 100%;
box-sizing: border-box;
border: 1px solid #666;
box-shadow: 3px 3px 3px rgba(0,0,0,.3);
}
.moreselect .noshow{
display: none;
}
.moreselect_list_input{
width: 100%;
}
.moreselect_list_list{
height: 200px;
overflow-y: auto;
margin-top: 10px;
}
.moreselect_list_list li{
padding: 2px 0;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.moreselect_list_list li:hover{
background-color: #1967d2;
color: #fff;
}
html代码,放在之前select组件的地方就行
<div class="moreselect">
<div class="moreselect_show" id="moreselect_show_out">
<div class="moreselect_show_in">
<p id="moreselect_show"></p>
</div>
</div>
<div class="moreselect_list noshow" id="moreselect_list">
<input type="text" class="moreselect_list_input" id="moreselect_list_input">
<ul class="moreselect_list_list" id="moreselect_list_list"></ul>
</div>
<input type="hidden" name="moreselect_show_value" id="moreselect_show_value" value="">
</div>
js代码,需要传两个对象:list,是要显示的下拉列表;default_list,是默认显示哪一个,如果default_list是空,显示list的第一个
const list = {"1":"省供销社", "2": "省委政研室", "3": "省红十字会", "4": "省文联", "5": "省文史馆", "6": "云南省信访局", "7": "云南省科学技术协会", "8": "云南省社会主义学院云南省社会主义学院", "9": "云南省工商联"};
const default_list = {"2": "省委政研室"};
(function(){
if(Object.entries(list).length){
const moreselect_list_list = document.querySelector('#moreselect_list_list');
const moreselect_show = document.querySelector('#moreselect_show');
const moreselect_show_out = document.querySelector('#moreselect_show_out');
const moreselect_list_input = document.querySelector('#moreselect_list_input');
const moreselect_list = document.querySelector('#moreselect_list');
const moreselect_show_value = document.querySelector('#moreselect_show_value');
if(Object.entries(default_list).length){
moreselect_show.innerHTML = Object.values(default_list);
moreselect_show_value.value = Object.keys(default_list);
}else{
for(const i in list){
moreselect_show.innerHTML = list[i];
moreselect_show_value.value = i;
break;
}
}
moreselect_show_out.addEventListener('click', (event) => {
if(moreselect_list.classList.contains('noshow')){
moreselect_list.classList.remove('noshow');
}else{
moreselect_list.classList.add('noshow');
}
});
moreselect_list_input.addEventListener('input', (event) => {
let filter = {};
const data = moreselect_list_input.value;
if(data != null){
for(const ele in list){
if(list[ele].indexOf(data) !== -1){
filter[ele] = list[ele];
}
}
fill_list(filter);
}else{
fill_list(list);
}
});
fill_list(list);
function fill_list(list){
moreselect_list_list.innerHTML = '';
for(const ele in list){
const li = document.createElement('li');
li.setAttribute('data-val', ele);
li.textContent = list[ele];
li.addEventListener('click', () => {
moreselect_show.innerHTML = list[ele];
moreselect_show_value.value = ele;
moreselect_list.classList.add('noshow');
});
moreselect_list_list.appendChild(li);
}
}
}
})(list, default_list);