我有两个重叠的范围输入,这会产生多范围输入效果。
我想要它,以便每当对其中任何一个进行单击时,更改具有与新单击的值最接近的值的输入。不完全确定如何解决这个问题。
我怎么能这样做?
(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" />
&#13;
答案 0 :(得分:6)
您必须捕获元素上的鼠标事件,并计算它与高标记与低标记的接近程度,并根据该标记决定更新哪一个。此外,因为这些是两个堆叠的输入元素,您可能必须手动将事件传递给低范围输入。
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。
但有些附带条件:
dispatchEvent
以外的机制......如fireEvent
或其他。答案 1 :(得分:2)
这里有一些你可以使用的简单方法。虽然您可能想要自定义样式。
我正在根据它与光标的接近程度来改变滑块元素的z-index
JSFiddle
HTML
<input id='a' type='range' />
<input id='b' type='range' />
<label role='info'></label>
JS
var a = document.getElementById('a');
var b = document.getElementById('b');
a.onmousemove = function(e) {
MouseMove.call(a, e);
};
b.onmousemove = function(e) {
MouseMove.call(b, e);
};
var MouseMove = function(eventArg)
{
var max = parseInt(a.max),
min = parseInt(a.min),
diff = max - min,
clickPoint = eventArg.offsetX / a.offsetWidth,
clickPointVal = parseInt(diff * clickPoint) + min;
/* absolute distance from respective slider values */
var da = Math.abs(a.value - clickPointVal),
db = Math.abs(b.value - clickPointVal);
// Making the two sliders appear above one another only when no mouse button is pressed, this condition may be removed at will
if (!eventArg.buttons)
{
if (da < db)
{
a.style.zIndex = 2;
b.style.zIndex = 1;
}
else if (db < da)
{
b.style.zIndex = 2;
a.style.zIndex = 1;
}
}
document.querySelector('label').innerHTML = 'Red: ' + a.value + ', Green: ' + b.value + ', X: ' + eventArg.clientX;
}
CSS
input {
margin: 0px;
position: absolute;
left: 0px;
}
label {
display: inline-block;
margin-top: 100px;
}
#a {
z-index: 2;
}
#b {
z-index: 1;
}