原生JavaScript+Css模拟Select下拉框


一、前言

各位FEer,你们好! 在我们的前端开发生涯中,有着许许多多的细枝末节,有的需要兼容低版本ie浏览器,有的是因为需要有更好的用户体验。最近呢,我们公司要为产品中心设计一个官方推广网站,其中的Select下拉框就因为设计师的交互靠原生不能很好的实现,以及效果,所以我就对Select进行了模拟的实现,一起来看看吧。

二、实现细节

涉及到的技术

考虑到兼容型以及最轻量化,我们就没有引用Jquery等,使用原生Javascript和Css来实现select的模拟。

效果展示







三、代码展示

Html结构

<div class="select-box">
    <input type="text" class="select-input" value="" readonly placeholder="地区 省" />
    <ul class="options-box hide">
      <li value="1">北京市</li>
      <li value="2">上海市</li>
      <li value="3">天津市</li>
      <li value="4">重庆市</li>
      <li value="5">河北省</li>
      <li value="6">河南省</li>
      <li value="6">江苏省</li>
      <li value="6">云南省</li>
    </ul>
  </div>

Css结构

/* 公共样式 */
    *,
    body {
      padding: 0;
      margin: 0;
      list-style: none;
      font-size: 14px;
      user-select: none;
      -webkit-user-select: none;
      -moz-user-select: none;
      -ms-user-select: none;
    }

    .hide {
      display: none;
    }

    /* 模拟下拉框 */
    .select-box {
      position: relative;
      margin: 50px 0 0 100px;
    }

    .select-box .select-input {
      line-height: 20px;
      border: 1px solid #d6d6d6;
      cursor: pointer;
      width: 170px;
      height: 50px;
      border: 1px solid transparent;
      outline: none;
      border-radius: 30px;
      -webkit-border-radius: 30px;
      -moz-border-radius: 30px;
      text-indent: 30px;
      font-size: 16px;
      font-weight: 400;
      /* color: rgba(187, 187, 187, 1); */
      color: rgba(34, 34, 34, 1);
      line-height: 22px;
      margin: 0;
      background: rgba(247, 247, 247, 1) url('./static/imgs/arrow-down.png') no-repeat scroll 130px center;
      background-size: 20px 20px;
      cursor: pointer;
      box-sizing: border-box;
    }

    /** input placeholder颜色改变 **/
    .select-box .select-input::-webkit-input-placeholder {
      /* WebKit browsers */
      color: rgba(187, 187, 187, 1);
    }

    .select-box .select-input:-moz-placeholder {
      /* Mozilla Firefox 4 to 18 */
      color: rgba(187, 187, 187, 1);
    }

    .select-box .select-input::-moz-placeholder {
      /* Mozilla Firefox 19+ */
      color: rgba(187, 187, 187, 1);
    }

    .select-box .select-input:-ms-input-placeholder {
      /* Internet Explorer 10+ */
      color: rgba(187, 187, 187, 1);
    }

    .select-box .select-input.isActive {
      background-color: #ffffff;
      border: 1px solid rgba(204, 204, 204, 1);
      background-image: url(./static/imgs/arrow-up.png);
    }

    .select-box .options-box {
      position: absolute;
      top: 55px;
      left: 0;
      width: 170px;
      overflow-y: scroll;
      overflow-x: hidden;
      width: 170px;
      height: 225px;
      background: rgba(255, 255, 255, 1);
      box-shadow: 0px 2px 8px 0px rgba(0, 0, 0, 0.25);
      border-radius: 5px;
    }

    .select-box .options-box li {
      width: 170px;
      height: 45px;
      text-indent: 30px;
      cursor: pointer;
      font-size: 16px;
      font-weight: 400;
      color: rgba(34, 34, 34, 1);
      line-height: 45px;
      background: rgba(255, 255, 255, 1);
    }

    .select-box .options-box li.active {
      background-color: rgba(247, 247, 247, 1);
      color: rgba(2, 176, 159, 1)
    }

JavaScript结构

window.onload = function () {
    // 判断是否有某个class
    function hasClass(ele, cls) {
      return ele.className.match(new RegExp("(\\s|^)" + cls + "(\\s|$)"));
    }
    // //为指定的dom元素添加样式
    function addClass(ele, cls) {
      if (!hasClass(ele, cls)) ele.className += " " + cls;
    }
    // //删除指定dom元素的样式
    function removeClass(ele, cls) {
      if (hasClass(ele, cls)) {
        var reg = new RegExp("(\\s|^)" + cls + "(\\s|$)");
        ele.className = ele.className.replace(reg, " ");
      }
    }
    // //如果存在(不存在),就删除(添加)一个样式
    // function toggleClass(ele, cls) {
    //   if (hasClass(ele, cls)) {
    //     removeClass(ele, cls);
    //   } else {
    //     addClass(ele, cls);
    //   }
    // }

    document.getElementsByClassName('select-input')[0].onclick = function () {
      var optionsBox = document.getElementsByClassName('options-box')[0];
      var selectInput = document.getElementsByClassName('select-input')[0];
      // 这里最好用children,不要用childNode, 否则会有多余的text节点
      var lis = optionsBox.children;
      if (hasClass(optionsBox, 'hide')) { // 如果当前不是正在打开选项状态
        removeClass(optionsBox, 'hide')
        addClass(selectInput, 'isActive')
        for (var i = 0; i < lis.length; i++) {
          if (lis[i].innerHTML == selectInput.value) { // 如果之前已经选择过,将之前的选项激活状态
            addClass(lis[i], 'active')
          } else {
            removeClass(lis[i], 'active')
          }
        }
      } else {
        addClass(optionsBox, 'hide');
        removeClass(selectInput, 'isActive');
      }
    }

    document.getElementsByClassName('options-box')[0].onclick = function (e) {
      var optionsBox = document.getElementsByClassName('options-box')[0];
      var selectInput = document.getElementsByClassName('select-input')[0];
      //这一行及下一行是为兼容IE8及以下版本
      e = e || window.event;
      var target = e.target || e.srcElement;
      if (target.tagName.toLowerCase() === "li") {
          // 将选中的值赋值给展示框文本
        selectInput.value = target.innerHTML;
        // 关闭选择列表
        addClass(optionsBox, 'hide');
        // 取消展示框的激活状态
        removeClass(selectInput, 'isActive');
      }
    }
    
    // 列表中选项滑过效果
    document.getElementsByClassName('options-box')[0].onmouseover = function (e) {
    // 事件代理
      var optionsBox = document.getElementsByClassName('options-box')[0];
      var selectInput = document.getElementsByClassName('select-input')[0];
      e = e || window.event;
      var target = e.target || e.srcElement;
      if (target.tagName.toLowerCase() === "li") {
        if (target.innerHTML != selectInput.value) { //如果滑过的不是已经选中的,给予暂时的滑过效果
          addClass(target, 'active');
        }
      }
    }

    document.getElementsByClassName('options-box')[0].onmouseout = function (e) {
      var optionsBox = document.getElementsByClassName('options-box')[0];
      var selectInput = document.getElementsByClassName('select-input')[0];
      //这一行及下一行是为兼容IE8及以下版本
      e = e || window.event;
      var target = e.target || e.srcElement;
      if (target.tagName.toLowerCase() === "li") {
        if (target.innerHTML != selectInput.value) { // 如果滑出的不是已经选中的,将滑过的效果取消
          removeClass(target, 'active');
        }
      }
    }
  }

总结

用原生JavsScript去实现效果的时候,可能有时候会比较麻烦,但是这是根本,其他的框架也好,第三方插件也罢,其实都可以理解为基于它而衍生的语法糖或者简化调用的集合。所谓万变不离其宗,谢谢各位同学,如果这篇文章对您有用的话,麻烦记得点赞收藏哦!

声明:Xuhao's Blog|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - 原生JavaScript+Css模拟Select下拉框


Carpe Diem and Do what I like