js实现下拉框可输入

前言

众所周知,html默认的下拉框是无法输入值的,然后最新的办法是用datalist和输入框绑定,但是很多浏览器不支持。然后还有很多框架提供的下拉框都是可输入的。但是公司的项目太老了,考虑到依赖性需要使用原生js去实现。

业务是这样,现在有一个输入框存在,需要在不改变这个输入框id的情况下让这个输入框能实现下拉框的效果。

代码实现

Js代码

我编写了一个函数用于接收元素id和下拉框的列表数据,函数内部需要完成下拉框的创建。

首先获取需要变成下拉框的输入框id,然后创建ul元素,然后为ul元素添加css属性,css代码在文章结尾。通过循环去创建li元素,在循环的内部不仅要创建li元素,还要为每个li设置data-key自定义属性作为下拉框的key。还需要为每个下拉框创建点击事件,也就是选中下拉框某个内容时,将li的内容赋值给input框,然后隐藏下拉框因为已经完成了选中操作。

hideOtherDropdowns隐藏未使用的下拉框,当我有多个下拉框的时候,点击第一个下拉框,再点击第二个下拉框的时候要让之前的下拉框隐藏,防止多个下拉框同时展开。

然后还需要为input框添加点击事件,当我点击input框的时候显示下拉列表,还需要为每个document添加点击事件,我点击其他dom的时候下拉框要隐藏,比如其他输入框,页面空白处。

最后将ul元素添加到input元素后面,并设置为relative定位模式。

window.addEventListener("DOMContentLoaded", function() {
    var options = [
      { key: "1", value: "选项1" },
      { key: "2", value: "选项2" },
      { key: "3", value: "选项3" },
      { key: "4", value: "选项4" }
    ];
    renderDropdown("test", options);
    renderDropdown("test2", options);
});

function renderDropdown(id, options) {
  var input = document.getElementById(id);
  var dropdown = document.createElement("ul");
    
  dropdown.classList.add("dropdown-options");

  for (var i = 0; i < options.length; i++) {
    var option = document.createElement("li");
    option.textContent = options[i].value;
    option.setAttribute("data-key", options[i].key);
    option.addEventListener("click", function() {
          input.value = this.textContent; // 将选中的值赋给 input
          var selectedKey = this.getAttribute("data-key");
          console.log("Selected key:", selectedKey);
          dropdown.classList.remove("show");
          console.log(input.value)
    });
    dropdown.appendChild(option);
  }

  function hideOtherDropdowns() 
  { 
    var otherDropdowns = document.querySelectorAll(".dropdown-options"); 
    for (var j = 0; j < otherDropdowns.length; j++) 
    { if (otherDropdowns[j] !== dropdown)
       { 
        otherDropdowns[j].classList.remove("show"); 
      } 
    } 
  } 
  input.addEventListener("click", function(e) {
    hideOtherDropdowns();
     //e.stopPropagation()的作用是阻止事件冒泡,使事件只在当前元素上触	发执行,不会继续传播到其他元素上。
    e.stopPropagation();
    dropdown.classList.toggle("show");
  });

  document.addEventListener("click", function() {
    dropdown.classList.remove("show");
  });

  input.insertAdjacentElement("afterend", dropdown);
  input.parentNode.style.position = "relative"; // 设置父元素的定位为相对定位
}

Css代码

.test {
  position: relative;
  width: 200px;
  padding: 10px;
  border: 1px solid #ccc;
  cursor: pointer;
  background-color: #fff;
}
.dropdown-options {
  position: absolute;
  left: 0;
  width: auto;
  max-height: 200px;
  overflow-y: auto;
  list-style-type: none;
  margin: 0;
  padding: 0;
  background-color: #fff;
  border: 1px solid #ccc;
  border-top: none;
  z-index: 999;
  display: none;
}
.show{
    display: block;
}
.dropdown-options li {
  padding: 10px;
  cursor: pointer;
}
.dropdown-options li:hover {
  background-color: #f2f2f2;
}

Html代码

<input id="test" type="text" class="test" placeholder="请选择"/>
<br/>
<input id="test2" type="text" class="test" placeholder="请选择"/>

实现效果

微信截图_20231018215318

微信截图_20231018215401