自定義下拉列表

自定義下拉列表:

選中項左側標記、自定義滾動條樣式、上下鍵滾動列表,回撤確認、事件委託

效果圖:

 

代碼:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>select</title>
  <style>
    body {
      background: #999999;
    }

    .baseSelect {
      height: 30px;
      width: 120px;
      background-color: #252833;
      color: rgba(255, 255, 255, 0.692);
      font-size: 16px;
      border-radius: 3px;
      outline: none;
    }

    .baseSelect option {
      display: none;
    }

    .selectPanel {
      display: inline-block;
    }

    .selectPopupPanel {
      position: absolute;
      margin-left: 1px;
      border-radius: 2px;
      box-shadow: 1px 2px 10px 0 rgba(0, 0, 0, 0.5);
      border: solid 1px rgba(213, 213, 213, 0.13);
      background-color: #252833;
      cursor: pointer;
      outline: none;
      display: none;
      overflow: hidden;
    }

    .selectPopupPanel .scrollBar {
      position: absolute;
      top: 0;
      right: 0;
      width: 4px;
      background-color: transparent;
    }

    .selectPopupPanel .scrollBar .slidBlock {
      position: relative;
      width: 100%;
      border-radius: 2px;
      background-color: #3d4351;
    }

    .selectOptions {
      overflow-x: hidden;
      overflow-y: scroll;
      background-color: #252833;
      margin-right: -100px;
    }

    .selectOptions .option {
      width: 100%;
      height: 42px;
      background-color: transparent;
    }

    .selectOptions .option .tag {
      float: left;
      width: 4px;
      height: 100%;
    }

    .selectOptions .option:hover, .selectOptions .optionSelected {
      background-color: #343743;
    }
    .selectOptions .optionSelected .tag {
      background-image: linear-gradient(5deg, #ff5858 15%, #f857a6 80%);
    }

    .selectOptions .option .optionText {
      float: left;
      line-height: 42px;
      padding-left: 10px;
      text-align: center;
      font-family: Roboto;
      font-size: 16px;
      font-weight: normal;
      font-stretch: normal;
      font-style: normal;
      letter-spacing: normal;
      color: #b1b8c8;
      user-select: none;
    }
  </style>
</head>

<body>
  <div>item:</div>
  <div class="selectPanel" style="margin-top: 200px;" id="s1">
    <select class="baseSelect">
      <option value="1">item1</option>
      <option value="2">item2</option>
      <option value="3">item3</option>
      <option value="4">item4</option>
      <option value="5">item5</option>
      <option value="6">item6</option>
      <option value="7">item7</option>
      <option value="8">item8</option>
      <option value="9">item9</option>
    </select>

    <div class="selectPopupPanel" tabindex="9999">
      <div class="selectOptions"></div>
      <div class="scrollBar">
        <div class="slidBlock"></div>
      </div>
    </div>
  </div>

  <script>
    function initSelect(value) {
      let selectCompon = null;
      if(typeof value == "string") {
        selectCompon = document.getElementById(value);
      } else {
        selectCompon = value;
      }
      let select = selectCompon.getElementsByClassName("baseSelect")[0];
      let selectPopupPanel = selectCompon.getElementsByClassName("selectPopupPanel")[0];

      select.onclick = function () {
        showSelectList(selectPopupPanel);
        initSelectList(select, selectPopupPanel);
      };

      function getTop(e) {
        var offset = e.offsetTop;
        if (e.offsetParent != null) offset += getTop(e.offsetParent);
        return offset;
      }

      function initSelectList(select, selectPopupPanel) {
        let options = select.options;
        let optionsCount = options.length;
        if(optionsCount == 0) {
          return;
        }

        let selectOptionsPanel = selectPopupPanel.getElementsByClassName("selectOptions")[0];
        let divOptionsHtml = "";
        for(let i=0; i<optionsCount; i++) {
          divOptionsHtml += 
          '<div data="'+options[i].value+'" class="option">' +
            '<div class="tag"></div>' +
            '<div class="optionText">'+options[i].text+'</div>' +
          '</div>';
        }
        selectOptionsPanel.innerHTML = divOptionsHtml;

        let scrollBar = selectPopupPanel.getElementsByClassName("scrollBar")[0]
        let slidBlock = selectPopupPanel.getElementsByClassName("slidBlock")[0];
        let divOptions = selectOptionsPanel.getElementsByClassName("option");
        let scrollHeight = selectOptionsPanel.scrollHeight;
        let panelHeight = scrollHeight;
        let selectBottom = getTop(select) + select.clientHeight;
        let windowHeight = window.innerHeight;
        let marginTop = 0;
        let showScrollBar = false;
        let lastSelectedIndex = select.selectedIndex;
        let selectedValue = function (index) {
          selectOptionsPanel.scrollTop = selectOptionsPanel.scrollHeight * index / optionsCount;
          divOptions[lastSelectedIndex].setAttribute("class", "option");
          divOptions[index].setAttribute("class", "option optionSelected");
          select.value = options[index].value;
          lastSelectedIndex = index;
        };

        selectedValue(select.selectedIndex);

        if (windowHeight - selectBottom < panelHeight) {
          if (selectBottom - select.clientHeight > windowHeight / 2) {
            let maxHeight = selectBottom - select.clientHeight - 50;
            if (panelHeight > maxHeight) {
              panelHeight = maxHeight;
              showScrollBar = true;
            }
            marginTop = -panelHeight - select.clientHeight - 3;
          } else {
            panelHeight = windowHeight - selectBottom - 20;
            showScrollBar = true;
          }
        }

        selectPopupPanel.style.width = select.clientWidth - 2 + "px";
        selectPopupPanel.style.marginTop = marginTop + "px";
        selectOptionsPanel.style.maxHeight = panelHeight + "px";
        
        selectPopupPanel.onblur = function() {
          hideSelectList(selectPopupPanel);
        }

        let selectOptionsPanelTop = getTop(selectOptionsPanel);
        selectOptionsPanel.onclick = function(e) {
          let index = Math.floor(optionsCount * (e.clientY-selectOptionsPanelTop + selectOptionsPanel.scrollTop) / scrollHeight);
          if(index >= optionsCount) {
            index = optionsCount - 1;
          }
          changeSelectValue(options[index].value);
          hideSelectList(selectPopupPanel);
        }

        if (showScrollBar) {
          scrollBar.style.display = "block";
          scrollBar.style.height = panelHeight + "px";
          let scrollHandle = function () {
            let scale = 1.0 * panelHeight / scrollHeight;
            let scrollBarHeight = panelHeight * scale;
            let scrollBarTop = selectOptionsPanel.scrollTop * scale;
            slidBlock.style.marginTop = scrollBarTop + "px";
            slidBlock.style.height = scrollBarHeight + "px";
          };
          selectOptionsPanel.scrollTop = 0;
          selectOptionsPanel.onscroll = scrollHandle;
          scrollHandle();
        } else {
          scrollBar.style.display = "none";
        }

        selectPopupPanel.onkeydown = function (event) {
          let e = event || arguments.callee.caller.arguments[0];
          if (!e) {
            return;
          }
          let keyCode = e.keyCode;
          if (keyCode != 38 && keyCode != 40 && keyCode != 13) {
            return;
          }
          let lastTime = selectPopupPanel.lastTime || 0;
          let nowTime = new Date().getTime();
          if (nowTime - lastTime < 80) {
            return;
          }
          selectPopupPanel.lastTime = nowTime;
          let index = select.selectedIndex;
          if (keyCode == 38) {
            if (index > 0) {
              selectedValue(--index);
            }
          } else if (keyCode == 40) {
            if (index + 1 < optionsCount) {
              selectedValue(++index);
            }
          } else if (keyCode == 13) {
            changeSelectValue(options[index].value);
          }
        };
      }

      function hideSelectList(selectPopupPanel) {
        if (selectPopupPanel.style.display == "none") {
          return;
        }
        setTimeout(function () {
          selectPopupPanel.style.display = "none";
        }, 50);
      }

      function showSelectList(selectPopupPanel) {
        if (selectPopupPanel.style.display == "block") {
          return;
        }
        selectPopupPanel.style.display = "block";
        selectPopupPanel.focus();
      }

      function changeSelectValue(value) {
        select.value = value;
        hideSelectList(selectPopupPanel);
        select.dispatchEvent(new Event("change"));
      }
    }
    initSelect("s1");
  </script>
  <script>
    var s = document.getElementById("s1").getElementsByClassName("baseSelect")[0];
    s.onchange = function(e) {
      console.log("select:" + e.target.value);
    }
  </script>
</body>

</html>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章