【问题标题】:Snap to Ticks and move Ticks position in Custom Range slider捕捉到刻度并在自定义范围滑块中移动刻度位置
【发布时间】:2021-07-31 22:03:11
【问题描述】:

我对此很陌生,我正在尝试弄清楚如何解决我的问题。 我正在尝试设计一个 Range 滑块来控制机器应用程序的速度。 我已经在这里搜索了好几个小时,但我找不到适合我的问题的结果。 我在这里添加的代码是我在其他页面上找到的,所以它可能不是最好的解决方案。

一开始我想用它做 3 件不同的事情。

  1. 第一个问题是我希望手柄捕捉到我所做的刻度,是否可以使用代码来做到这一点,所以如果我更改我的刻度,手柄仍然会捕捉到新的刻度?
  2. 是否有可能在 0 到 10% 之间有更多的刻度,所以我有 2% 的步长到 10%,当手柄在那里时,它会捕捉到 2% 的步长,当它超过 10% 时它会捕捉到另外 10% 的步长间隔。
  3. 是否可以将刻度移动到滑块内并将标签放在中间? 我想在底部和顶部都有刻度,然后在中间有标签。我附上了一张我的目标的图片。

非常感谢

Range slider idea!

链接到我的代码

https://www.w3schools.com/code/tryit.asp?filename=GT1V8EFG2RUA

【问题讨论】:

    标签: javascript html css input webkit


    【解决方案1】:

    function toggleStep(element) {
      if (element.value >= 10) { element.step = 10; }
      else { element.step = 2; }
    }
    
    /**
     * Sniffs for Older Edge or IE,
     * more info here:
     * https://stackoverflow.com/q/31721250/3528132
     */
    function isOlderEdgeOrIE() {
      return (
        window.navigator.userAgent.indexOf("MSIE ") > -1 ||
        !!navigator.userAgent.match(/Trident.*rv\:11\./) ||
        window.navigator.userAgent.indexOf("Edge") > -1
      );
    }
    
    function valueTotalRatio(value, min, max) {
      return ((value - min) / (max - min)).toFixed(2);
    }
    
    function getLinearGradientCSS(ratio, leftColor, rightColor) {
      return [
        '-webkit-gradient(',
        'linear, ',
        'left top, ',
        'right top, ',
        'color-stop(' + ratio + ', ' + leftColor + '), ',
        'color-stop(' + ratio + ', ' + rightColor + ')',
        ')'
      ].join('');
    }
    
    function updateRangeEl(rangeEl) {
      var ratio = valueTotalRatio(rangeEl.value, rangeEl.min, rangeEl.max);
    
      rangeEl.style.backgroundImage = getLinearGradientCSS(ratio, '#00FF00', '#c5c5c5');
    }
    
    function initRangeEl() {
      var rangeEl = document.querySelector('input[type=range]');
      var textEl = document.querySelector('input[type=text]');
    
      /**
       * IE/Older Edge FIX
       * On IE/Older Edge the height of the <input type="range" />
       * is the whole element as oposed to Chrome/Moz
       * where the height is applied to the track.
       *
       */
      if (isOlderEdgeOrIE()) {
        rangeEl.style.height = "20px";
        // IE 11/10 fires change instead of input
        // https://stackoverflow.com/a/50887531/3528132
        rangeEl.addEventListener("change", function(e) {
          textEl.value = e.target.value;
        });
        rangeEl.addEventListener("input", function(e) {
          textEl.value = e.target.value;
        });
      } else {
        updateRangeEl(rangeEl);
        rangeEl.addEventListener("input", function(e) {
          updateRangeEl(e.target);
          textEl.value = e.target.value;
        });
      }
    }
    
    initRangeEl();
    .slidecontainer {
      width: 500px;
      margin-left:15px;
    }
    
    input[type="range"] {
      -webkit-appearance: none;
      -moz-appearance: none;
      width:100%;
      height: 50px;
      padding: 0;
      border: solid 2px #000000;
      border-radius: 8px;
      outline: none;
      cursor: pointer;
    }
    
    datalist {
      display: flex;
      margin-left: 2px;
      margin-top: -50px;
    }
    
    datalist option {
      flex-basis: 10%;
      border-left: 1px solid #000;
    }
    datalist option:nth-child(-n+5) {
      flex-basis: 2%;
    }
    datalist option:last-child {
      display: none;
    }
    
    /*Chrome thumb*/
    
    input[type="range"]::-webkit-slider-thumb {
      -webkit-appearance: none;
      -moz-appearance: none;
      -webkit-border-radius: 5px;
      /*16x16px adjusted to be same as 14x14px on moz*/
      height: 45px;
      width: 45px;
      border-radius: 5px;
      background: #e7e7e7;
      border: 2px solid #000000;
      opacity: 0.4;
      cursor: pointer;
      border-radius: 8px; 
    
    }
    
    
    /*Mozilla thumb*/
    
    input[type="range"]::-moz-range-thumb {
      -webkit-appearance: none;
      -moz-appearance: none;
      -moz-border-radius: 5px;
      height: 14px;
      width: 14px;
      border-radius: 5px;
      background: #e7e7e7;
      border: 1px solid #c5c5c5;
    }
    
    
    /*IE & Edge input*/
    
    input[type=range]::-ms-track {
      width: 300px;
      height: 6px;
      /*remove bg colour from the track, we'll use ms-fill-lower and ms-fill-upper instead */
      background: transparent;
      /*leave room for the larger thumb to overflow with a transparent border */
      border-color: transparent;
      border-width: 2px 0;
      /*remove default tick marks*/
      color: transparent;
        margin-left:15px;
    }
    
    
    /*IE & Edge thumb*/
    
    input[type=range]::-ms-thumb {
      height: 14px;
      width: 14px;
      border-radius: 5px;
      background: #e7e7e7;
      border: 1px solid #c5c5c5;
    }
    
    
    /*IE & Edge left side*/
    
    input[type=range]::-ms-fill-lower {
      background: #000000;
      border-radius: 2px;
        margin-left:15px;
    }
    
    
    /*IE & Edge right side*/
    
    input[type=range]::-ms-fill-upper {
      background: #000000;
      border-radius: 2px;
    }
    
    
    /*IE disable tooltip*/
    
    input[type=range]::-ms-tooltip {
      display: none;
    }
    
    input[type="text"] {
      border: none;
    }
    
    
    .sliderticks {
      display: flex;
      justify-content: space-between;
      padding: 0 50px;
    }
    
    .sliderticks p {
      position: relative;
      display: flex;
      justify-content: center;
      text-align: center;
      width: 1px;
      background: #D3D3D3;
      height: 10px;
      line-height: 40px;
      margin: 0 0 20px 0;
    }
    <h1>Custom Range Slider</h1>
    <p>Drag the slider to display the current value.</p>
    
    <div class="slidecontainer">
    <input type="range" value="10" min="0" max="100" oninput="toggleStep(this)" list="sliderticks"   />
    
    <div class="datalist">
     <datalist id="sliderticks">
       <option>0</option>
       <option>2</option>
       <option>4</option>
       <option>6</option>
       <option>8</option>
       <option>10</option>
       <option>20</option>
       <option>30</option>
       <option>40</option>
       <option>50</option>
       <option>60</option>
       <option>70</option>
       <option>80</option>
       <option>90</option>
       <option>100</option>
     </datalist>
    </div>
    
    </div>

    【讨论】:

      【解决方案2】:

      希望下面的代码能解决您的需求:

      document.querySelectorAll('.range input[type="range"]').forEach((range) => {
        range.tickmarks = [...range.list.options].map((el) => parseFloat(el.value));
        range.list.insertAdjacentHTML('afterend', `<div class="range-value"></div>`);
        range.max = parseFloat(range.tickmarks[range.tickmarks.length - 1]);
        let q = (range.clientWidth - 40) / range.max;
        range.addEventListener('input', function(ev) {
          if (this.hasAttribute('ticks-only')) {
            this.value = range.tickmarks.map((x) => x).sort((x, y) => Math.abs(x - this.value) - Math.abs(y - this.value))[0];
          }
          this.parentElement.style.backgroundSize = `${(this.value * range.clientWidth) / range.max}px 100%, 100% 100%`;
          this.list.nextElementSibling.textContent = this.value;
          this.list.nextElementSibling.style.left = `${20 + this.value * q}px`;
        });
        range.tickmarks.forEach((el, i) => {
          range.list.options[i].label = el % 10 ? ' ' : el;
          range.list.options[i].style.left = 20 + el * q + 'px';
        });
        range.dispatchEvent(new Event('input', {bubbles: true}));
      });
      .range {
        position: relative;
        height: 52px; width: 500px;
        border-radius: 0.125em;
        overflow: hidden;
        font: 16px/1em sans-serif;
        background-image: linear-gradient(to right, #7bad23, #39594c), linear-gradient(to bottom, #84929d, #46576d);
        background-size: 0 100%, 100% 100%;
        background-repeat: no-repeat;
        box-shadow: 0 0 0 0.125em #7f8c97, 0.0625em 0.125em 0.3125em 0em #93a2bd, -0.125em -0.1875em 0.3125em 0em #0e1116, inset 0 0 1.25em -0.3125em #0e1116;
      }
      
      datalist {
        position: relative;
        display: block;
        height: 100%; width: 100%;
        pointer-events: none;
      }
      
      .range datalist option {
        position: absolute !important;
        display: grid;
        place-items: center;
        height: 100%;
        padding: 0;
        transform: translatex(-50%);
        font: bold 12px/1em monospace !important;
        text-shadow: 1px 0 0.16666667em #fff5;
      }
      
      .range datalist option::before,
      .range datalist option::after {
        content: "";
        position: absolute;
        left: 50%;
        height: 100%; width: 0;
        box-shadow: 0 0 0 0.08333333em #0008;
      }
      .range datalist option::before { bottom: calc(50% + 1em); }
      .range datalist option::after { top: calc(50% + 1em); }
      
      input[type="range"] {
        appearance: none;
        position: absolute;
        top: 0; left: 0; z-index: 1;
        margin: 0;
        height: 100%; width: 100%;
        box-sizing: border-box;
        font: inherit;
        background-color: transparent;
        cursor: pointer;
      }
      
      input[type="range"]::-webkit-slider-thumb {
        appearance: none;
        display: block;
        width: 2.5em; height: 2.5em;
        border: none;
        border-radius: 0.75em;
        background-color: #99c7;
        box-shadow: 0 0 0.125em 0 #282850dd, inset 0 0 0.125em 0.125em #282850dd;
        transition: background-color 0.5s ease-out 0.5s;
      }
      input[type="range"]:active::-webkit-slider-thumb {
        background-color: #fff8;
        transition: background-color 0.5s ease-out;
      }
      
      .range-value {
        position: absolute;
        top: 0; left: 0; z-index: 2;
        display: grid;
        place-items: center;
        height: 100%;
        transform: translatex(-50%);
        font: bold 12px/1em monospace !important;
        text-shadow: 0 0 0.16666667em #fff;
        opacity: 0;
        pointer-events: none;
        transition: opacity 1s ease-in;
      }
      input[type="range"]:focus-visible~.range-value,
      input[type="range"]:active~.range-value,
      input[type="range"]:hover~.range-value {
        opacity: 1;
        transition: opacity 0.5s ease-out;
      }
      
      body { margin: 0; height: 100vh; background-color: #42516c; display: flex; flex-flow: column nowrap; justify-content: center; align-items: center; }
      <div class="range">
        <input type="range" list="high">
        <datalist id="high">
          <option value="0">
          <option value="2">
          <option value="4">
          <option value="6">
          <option value="8">
          <option value="10">
          <option value="20">
          <option value="30">
          <option value="40">
          <option value="50">
          <option value="60">
          <option value="70">
          <option value="100">
        </datalist>
      </div>
      <h3>With "ticks-only" attribute</h3>
      <div class="range">
        <input type="range" list="bass" ticks-only>
        <datalist id="bass">
          <option value="0">
          <option value="10">
          <option value="15">
          <option value="20">
          <option value="30">
          <option value="40">
          <option value="50">
          <option value="60">
          <option value="70">
          <option value="72">
          <option value="74">
          <option value="76">
          <option value="78">
          <option value="80">
          <option value="100">
          <option value="175">
          <option value="200">
        </datalist>
      </div>

      注意!此代码仅适用于“webkit”(在 Chrome 中测试)。当父元素和子元素设置为“absolute”时,Firefox 无法正确使用“position”属性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-08-15
        • 1970-01-01
        • 2020-10-21
        • 2015-10-16
        • 1970-01-01
        • 1970-01-01
        • 2019-04-11
        • 1970-01-01
        相关资源
        最近更新 更多