今天遇到一个问题,就是layui.js的下拉框模糊查询功能并不能满足我的需求,因此我动手自己写了一个下拉框。

实现思路其实就是,模仿layui.js的下拉框样式,然后监听input的输入事件,一旦输入,就调接口,让后台返给我查到的数据。

还是上代码吧:

html:

<form action="">
  <div class="box">
    <div class="select-container">
      <div class="select-title">
        <input type="text" class="select-search-input" />
        <i class="select-down select-icon"></i>
      </div>
      <ul class="select-items"></ul>
    </div>
  </div>
  <button class="submit" type="submit">提交</button>
</form>

css:

body {
  background-color: #dcdbdb;
}
.box {
  width: 150px;
}
.select-container {
  position: relative;
}
.select-container > ul,
.select-container > ul li {
  list-style: none;
}
.select-container > .select-title {
  position: relative;
}
.select-container > .select-title > .select-search-input {
  height: 38px;
  border: 1px solid #e6e6e6;
  background-color: #ffffff;
  outline: none;
  border-radius: 2px;
  cursor: pointer;
  padding-left: 10px;
  padding-right: 22px;
  width: 100%;
  display: block;
  box-sizing: border-box;
}
.select-icon {
  position: relative;
  display: inline-block;
  vertical-align: middle;
  width: 0;
  height: 0;
  border-width: 6px;
  border-style: dashed;
  border-color: transparent;
  overflow: hidden;
}
.select-container > .select-title > .select-icon {
  position: absolute;
  right: 10px;
  top: 50%;
  cursor: pointer;
  border-top-color: #c2c2c2;
  border-top-style: solid;
  transition: all 0.3s;
  margin-top: -3px;
}
.select-container > .select-title > .select-up {
  margin-top: -9px;
  transform: rotate(180deg);
}
.select-container > .select-items {
  position: absolute;
  left: 0;
  top: 32px;
  padding: 5px 0;
  z-index: 899;
  min-width: 100%;
  border: 1px solid #d2d2d2;
  max-height: 300px;
  overflow-y: auto;
  background-color: #fff;
  border-radius: 2px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12);
  box-sizing: border-box;
}
.select-container > .select-items {
  display: none;
}
.select-container > .select-items .select-option {
  padding: 0 10px;
  line-height: 36px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
  transition: 0.5s all;
  background-color: #f2f2f2;
}
.select-container > .select-items .select-option:hover {
  background-color: #5fb878;
  color: #fff;
}
.select-container > .select-items > .select-this {
  background-color: #5fb878;
  color: #fff;
}

js:

 /*
 *  function:the ajax
 * params:interface url,request method,paramns,callback function
 */

function ewAjax(url, method, params, callback) {
  method = method.toUpperCase() === "GET" ? "GET" : "POST";
  var xhr = new XMLHttpRequest();
  if (method.toUpperCase() === "GET") {
    if (params) {
      url = url + params;
    }
    xhr.open(method, url);
    xhr.send();
  } else {
    if (typeof params === "string" && params) {
      xhr.open(method, url + "?" + params);
      xhr.send(JSON.stringify(params));
    } else if (params) {
      xhr.open(method, url);
      xhr.send(JSON.stringify(params));
    }
  }
  xhr.onreadystatechange = function() {
    if (xhr.readyState === 4 && xhr.status === 200) {
      callback(JSON.parse(xhr.responseText));
    }
  };
}

 /*
 *  function:Serialization parameters
 * params:params
 */

function ewParam(params) {
  var keys = Object.keys(params),
    key_len = keys.length;
  var str = "";
  for (var key in params) {
    str += key + "=" + params[key];
    if (key === keys[key_len - 1]) {
      break;
    } else {
      str += "&";
    }
  }
  return str;
}

 /*
 *  function:create the select component
 * params:params
 */

function createSelect(el1, el2, callback) {
  el1.oninput = function(e) {
    // get data
    ewAjax(url,"POST",ewParam({name: e.target.value}),function(res) {
        if (res.status === "200") {
          callback(res.data, el1, el2);
        }
      });
  };
}
var search_input = document.getElementsByClassName(
      "select-search-input"
    )[0],
    select_items = document.getElementsByClassName("select-items")[0];

  createSelect(search_input, select_items, function(data, el1, el2) {
    var li;
    if (data.length > 0) {
      el2.style.display = "block";
      el2.innerHTML = "";
      el1.nextElementSibling.classList.add("select-up");
    //   click the select arrow
      el1.nextElementSibling.onclick = function() {
        this.classList.toggle("select-up");
        if (this.className.indexOf("select-up") > -1) {
          el2.style.display = "block";
        } else {
          el2.style.display = "none";
        }
      };
      data.map(function(d, index) {
        li = document.createElement("li");
        // the value need to subbmit 
        li.setAttribute("data-value", d.id);
        // maybe you need to save the data by search
        li.setAttribute("data-info", JSON.stringify(d));
        li.textContent = d.name;
        li.className = "select-option";
        // the default select value
        if (index === 0) {
          li.classList.add("select-this");
        }
        li.onclick = function() {
          el2.style.display = "none";
          el1.value = this.textContent;
          el1.nextElementSibling.classList.remove("select-up");
        //change the value about submit the form data,so create a hidden input element
          var sm_input = document.createElement("input");
          sm_input.style.display = "none";
          sm_input.name = "name";
          sm_input.value = this.getAttribute("data-value");
          el1.parentElement.appendChild(sm_input);
        };
        el2.appendChild(li);
      });
    }
  });
  
  

其实整体思路也不算太难,无非就是当后台返给了数据之后,然后列表显示,给列表项添加点击事件,关于这个,给下拉箭头添加事件,控制列表的显隐,然后就没有什么了,分享出来,希望能帮助到跟我碰到一样的情况无法着手的人。代码已上传至git源码,觉得不错希望点个star,多谢。


夕水
5.2k 声望5.7k 粉丝

问之以是非而观其志,穷之以辞辩而观其变,资之以计谋而观其识,告知以祸难而观其勇,醉之以酒而观其性,临之以利而观其廉,期之以事而观其信。


下一篇 »
算法入门