javascript – 重叠范围输入.在点击更改输入时具有最接近的值

我有两个重叠的范围输入,这创建了一个多范围输入效果.

我想要它,以便每当对其中任何一个进行单击时,将更改具有与新单击的值最接近的值的输入.不完全确定如何解决这个问题.

我怎么能这样做?

(function() {
  "use strict";

  var supportsMultiple = self.HTMLInputElement && "valueLow" in HTMLInputElement.prototype;

  var descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value");

  self.multirange = function(input) {
    if (supportsMultiple || input.classList.contains("multirange")) {
      return;
    }

    var values = input.getAttribute("value").split(",");
    var max = +input.max || 100;
    var ghost = input.cloneNode();

    input.classList.add("multirange", "original");
    ghost.classList.add("multirange", "ghost");

    input.value = values[0] || max / 2;
    ghost.value = values[1] || max / 2;

    input.parentNode.insertBefore(ghost, input.nextSibling);

    Object.defineProperty(input, "originalValue", descriptor.get ? descriptor : {
      // Dang you Safari >:(
      get: function() {
        return this.value;
      },
      set: function(v) {
        this.value = v;
      }
    });

    Object.defineProperties(input, {
      valueLow: {
        get: function() {
          return Math.min(this.originalValue, ghost.value);
        },
        set: function(v) {
          this.originalValue = v;
        },
        enumerable: true
      },
      valueHigh: {
        get: function() {
          return Math.max(this.originalValue, ghost.value);
        },
        set: function(v) {
          ghost.value = v;
        },
        enumerable: true
      }
    });

    if (descriptor.get) {
      // Again, fuck you Safari
      Object.defineProperty(input, "value", {
        get: function() {
          return this.valueLow + "," + this.valueHigh;
        },
        set: function(v) {
          var values = v.split(",");
          this.valueLow = values[0];
          this.valueHigh = values[1];
        },
        enumerable: true
      });
    }

    function update() {
      ghost.style.setProperty("--low", input.valueLow * 100 / max + 1 + "%");
      ghost.style.setProperty("--high", input.valueHigh * 100 / max - 1 + "%");
    }

    input.addEventListener("input", update);
    ghost.addEventListener("input", update);

    update();
  }

  multirange.init = function() {
    Array.from(document.querySelectorAll("input[type=range][multiple]:not(.multirange)")).forEach(multirange);
  }

  if (document.readyState == "loading") {
    document.addEventListener("DOMContentLoaded", multirange.init);
  } else {
    multirange.init();
  }

})();
@supports (--css: variables) {
  input[type="range"].multirange {
    -webkit-appearance: none;
    padding: 0;
    margin: 0;
    display: inline-block;
    vertical-align: top;
    width: 250px;
    margin-top: 50px;
    margin-left: 50px;
    background: lightblue;
  }
  input[type="range"].multirange.original {
    position: absolute;
  }
  input[type="range"].multirange.original::-webkit-slider-thumb {
    position: relative;
    z-index: 2;
  }
  input[type="range"].multirange.original::-moz-range-thumb {
    transform: scale(1);
    /* FF doesn't apply position it seems */
    G z-index: 1;
  }
  input[type="range"].multirange::-moz-range-track {
    border-color: transparent;
    /* needed to switch FF to "styleable" control */
  }
  input[type="range"].multirange.ghost {
    position: relative;
    background: var(--track-background);
    --track-background: linear-gradient(to right, transparent var(--low), var(--range-color) 0, var(--range-color) var(--high), transparent 0) no-repeat 0 45% / 100% 40%;
    --range-color: hsl(190, 80%, 40%);
  }
  input[type="range"].multirange.ghost::-webkit-slider-runnable-track {
    background: var(--track-background);
  }
  input[type="range"].multirange.ghost::-moz-range-track {
    background: var(--track-background);
  }
}
<input type="range" multiple value="10,80" />
最佳答案
您必须在元素上捕获鼠标事件,并计算它与高标记与低标记的接近程度,并根据该标记决定更新哪一个.此外,因为这些是两个堆叠的输入元素,您可能必须手动将事件传递给低范围输入.

Here’s my go在创建这样一个功能:

function passClick(evt) {
  // Are the ghost and input elements inverted? (ghost is lower range)
  var isInverted = input.valueLow == ghost.value;
  // Find the horizontal position that was clicked (as a percentage of the element's width) 
  var clickPoint = evt.offsetX / this.offsetWidth;
  // Map the percentage to a value in the range (note, assumes a min value of 0)
  var clickValue = max * clickPoint;

  // Get the distance to both high and low values in the range
  var highDiff = Math.abs(input.valueHigh - clickValue);
  var lowDiff = Math.abs(input.valueLow - clickValue);

  if (lowDiff < highDiff && !isInverted || (isInverted && lowDiff > highDiff)) {
    // The low value is closer to the click point than the high value
    // We should update the low value input
    var passEvent = new MouseEvent("mousedown", {screenX: evt.screenX, clientX: evt.clientX});
    // Pass a new event to the low "input" element (which is obscured by the
    // higher "ghost" element, and doesn't get mouse events outside the drag handle
    input.dispatchEvent(passEvent);
    // The higher "ghost" element should not respond to this event
    evt.preventDefault();
    return false;
  }
  else {
    console.log("move ghost");
    // The high value is closer to the click point than the low value
    // The default behavior is appropriate, so do nuthin
  }
}

ghost.addEventListener("mousedown", passClick);

我把这段代码放在input.addEventListener(“input”,update)的正上方;您的样本中的行,它似乎工作.见我的fiddle.

但有些附带条件:

>我只在Chrome中测试过.根据我复制事件的方式,IE可能会遇到一些麻烦.它可能使用dispatchEvent以外的机制……比如fireEvent或者其他东西.
>最初我编码它假设“ghost”元素始终跟踪高范围.我已经更新了一些内容,以便在ghost元素具有较低值时反转事件调度 – 但我加快了速度.

转载注明原文:javascript – 重叠范围输入.在点击更改输入时具有最接近的值 - 代码日志