带搜索的下拉组件

最近遇到的这种需求比较多,直接花点时间封装了一个:

  • 完全原生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);

demo