ui组件——多选下拉input的实现(含有搜索功能)

ui组件——多选下拉input的实现(带有搜索功能)

先上效果图
ui组件——多选下拉input的实现(含有搜索功能)

ui组件——多选下拉input的实现(含有搜索功能)

ui组件——多选下拉input的实现(含有搜索功能)

废话不说 先看div层次结构

<!-- 最外层div 可以任意指定 主要用于定义子元素宽度 -->
        <div class="col-xs-10" style="width:800px">
          <!-- 表单label 添加文字提示 -->
          <label for="" class="label-control">全文检索</label>
          <!-- 多选承接div 以后会动态添加span -->
          <div class="hint-input-span-container">
            <!-- 表单元素 用来绑定监听事件以及接收用户输入 该层上方会动态添加span -->
            <input type="text" name="hint-search" value="" placeholder="选定关键字或按下tab或按下enter来分割关键字">
          </div>
          <!-- 包含下拉列表列 -->
          <div class="hint-block">
            <!-- 根据json数据包动态添加li -->
            <ul class="hint-ul">

            </ul>
          </div>
        </div>

dom结构注释已经能说得清楚了,下面来看css

* {
        box-sizing: border-box;
      }

      .hint-input-span-container {
        width:100%;
        background-color: #fff;
        border: 1px solid #ccc;
        box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
        display: inline-block;
        padding: 2px 4px;
        color: #555;
        vertical-align: middle;
        border-radius: 1px;
        max-width: 100%;
        line-height: 30px;
      }

      .hint-input-span-container .tag {
            padding: -2px;
            font-size: 12px;
            font-family: serif;;
            margin-right: 2px;
            margin-top: 2px;
            margin-bottom: 2px;
            display: inline-block;
      }

      .label {
        font-size: 10px;
        padding: 4px 6px;
        border: none;
        text-shadow: none;
        border-radius: 3px;
        font-weight: 200;
      }

      .label-primary {
        background: #2693FF;
        color: white;
      }

      .hint-input-span-container span i[data-role='remove'] {
        cursor: pointer;
      }

      .tag {
        margin-right: 2px;
        color: white;
      }

      .tag [data-role="remove"] {
        margin-left: 2px;
        cursor: pointer;
      }

      input[name='hint-search'] {
        border: none;
        box-shadow: none;
        outline: none;
        background-color: transparent;
        padding: 0;
        margin: 0;
        width: 100%;
        max-width: inherit;
      }

      .hint-block {
        position: absolute;
        width: 100px;
        max-height: 120px;
        background-color: #fff;
        overflow: auto;
        display: none;
        z-index: 9999;
      }

      .hint-ul {
        text-decoration: none;
        list-style-type: none;
        padding-left: 5px;
      }

      .hint-ul li{
        font-size: 14px;
        padding: 2px 4px;
      }

      .hint-ul li:hover{
        background-color: #eee;
      }

css中设置border-sizing:border-box很重要,这个属性可以使padding与border计算在width之中

.hint-input-span-container 设置display为inline-block也很重要,有关于tag的排列

.hint-block设置z-index为9999保证显示在最前端,同时position为absolute保证其位置

其他的都可以根据自己需要调整

下面来看js代码

$(function(){

  //json数据包
  var data = {data:["123","北京你好","北京欢迎您","北京好","海洋","海洋广利局","我海洋","我吃惊","我啦啦啦啦","我不能忍","机构","日本","俄罗斯的山","埃塞俄比亚","伊巴卡","比比比"]};
  //获取后面需要多次调用的dom对象
  var $hintSearch = $("input[name='hint-search']");
  var $hintSearchContainer = $(".hint-input-span-container");
  var $hintBlock = $(".hint-block");
  var $hintUl = $(".hint-ul");

  //初次调用添加词典
  addDictionary(data.data,addUlListener);
  //设置词典列表宽度
  setHintSearchContainerWidth();

  //实现响应式 监听resize事件
  $(window).bind('resize', setHintSearchContainerWidth);

  //获得焦点
  $hintSearch.focus(function(){
    animteDown();
  });

 //失去焦点
 //设置延迟为了可以监听到click的响应
 $hintSearch.blur(function(){
   setTimeout(function(){
     animateUp();
   },200);
 });

 //TAB 与 enter事件
 //监听tab与enter两个键位 如果input内有输入的内容,则添加span
 //注意最后要阻止一下事件冒泡 防止跳转与切换焦点
 $hintSearch.keydown(function(e){
   switch (e.which) {
     case 9: case 13:{

       var text = $hintSearch.val();

       if(!$.trim(text)) {
         $hintSearch.val("");
         e.preventDefault();
         return;
       }

       if( !checkContainerHas(text) ) {
         $hintSearch.before('<span class="tag label label-primary">'+ text +' <i class="fa fa-times" data-role="remove"></i><i>&nbsp;</i></span>');
         addSpanListenr();
       }
       //console.log($hintSearch.val());
       $hintSearch.val("");
       $hintSearch.focus();
       e.preventDefault();
       break;
     }
     default: ;

   }
 });

 //检测输入配对
 //对输入内容在li中进行匹配 如果包含字符串可以找到并返回
 //搜索方法可以自行修改,只要保证返回一个搜索后的数组即可
 $hintSearch.keyup(function(e){

   var text = $hintSearch.val();

   if (!$.trim(text)){
     updateDictionary(data.data,addUlListener);
   }

   var tmparr = data.data.filter(function(x){
     return x.indexOf(text) != -1;
   })

   if (tmparr.length === 0) {
     tmparr.push("无匹配条目");
   }

   updateDictionary(tmparr,addUlListener);
 })



  //函数库
  //添加用户常用字典库
  function addDictionary(dataarr, callback) {
    for(var i = 0; i < dataarr.length; i++) {
      $hintUl.append('<li>'+ dataarr[i] +'</li>');
    }
    callback();
  }

  //更新搜索内容
  function updateDictionary(dataarr,callback) {
    $hintUl.empty();
    addDictionary(dataarr,callback);
  }

  //向下滑动动画
  //封装改变样式边框
  function animteDown()
  {
    $hintBlock.slideDown('fast').css({'border':'1px solid #96C8DA','border-top' : '0px', 'box-shadow' : '0 2px 3px 0 rgba(34,36,38,.15)'});
    $hintSearchContainer.css({'border':'1px solid #96C8DA','border-bottom' : '0px', 'box-shadow' : '0 2px 3px 0 rgba(34,36,38,.15)'});

  }

  //向上滑动动画
  function animateUp()
  {
    $hintBlock.slideUp('fast',function(){
      $hintSearchContainer.css({'border':'1px solid #ccc'});
    });
  }

  //检验是否与输入的重复
  function checkContainerHas(text)
  {
    var flag = 0;
    $(".hint-input-span-container span").each(function(){
      if ($.trim(text) == $.trim($(this).text())) {
         flag = 1;
         return;
      }
    });
    return flag ? true : false;
  }
  //设置hint-input-span-container宽度
  function setHintSearchContainerWidth()
  {
    var hint_width = $hintSearchContainer.width() + 2 * parseInt($hintSearchContainer.css('padding-left').match(/[0-9]+/)[0]) +  2 * parseInt($hintSearchContainer.css('border-left').match(/[0-9]+/)[0]) ;
    $hintBlock.css({'width': hint_width});
  }


 //绑定click事件
 function addUlListener() {
   $hintUl.delegate('li','click',function(){
     var text = $(this).text();

     if(!checkContainerHas(text)) {
       $hintSearch.before('<span class="tag label label-primary">'+ text +' <i class="fa fa-times" data-role="remove"></i><i>&nbsp;</i></span>');
       addSpanListenr();
     }
     $hintSearch.val("");
     animateUp();
   })
 }

 //监听 span事件
 function addSpanListenr() {
   $(".hint-input-span-container span").delegate("i",'click',function(){
     $(this).parent().remove();
   })
 }
})

重点就是对事件的监听以及dom元素的操作,要依赖于jquery