问题是:使用范围输入时,即滑块,on('input'... 在 Mac 和 Windows Firefox、Chrome 和 Opera 以及 Mac Safari 中提供持续更新的范围值,而 on('change'... 仅在鼠标松开时报告范围值。相比之下,在 Internet Explorer(v11)中,on('input'... 根本不起作用,而 on('change'... 不断更新。
var rng = document.querySelector("input");
read("mousedown");
read("mousemove");
read("keydown"); // include this to also allow keyboard controlfunctionread(evtType) {
rng.addEventListener(evtType, function() {
window.requestAnimationFrame(function () {
document.querySelector("div").innerHTML = rng.value;
rng.setAttribute("aria-valuenow", rng.value); // include for accessibility
});
});
}
var rng = document.querySelector("input");
var listener = function() {
window.requestAnimationFrame(function() {
document.querySelector("div").innerHTML = rng.value;
});
};
rng.addEventListener("mousedown", function() {
listener();
rng.addEventListener("mousemove", listener);
});
rng.addEventListener("mouseup", function() {
rng.removeEventListener("mousemove", listener);
});
// include the following line to maintain accessibility// by allowing the listener to also be fired for// appropriate keyboard events
rng.addEventListener("keydown", listener);
table {border-collapse: collapse; font: 10pt Courier;}
th, td {border: solid black 1px; padding: 00.5em;}
input {margin: 2em;}
li {padding-bottom: 1em;}
<p>Click on 'Full page' to see the demonstration properly.</p><table><tr><th></th><th>event</th><th>range value</th><th>random update indicator</th></tr><trid="inp" ><td>A</td><td>input </td><td>100</td><td>-</td></tr><trid="chg" ><td>B</td><td>change </td><td>100</td><td>-</td></tr><trid="mdn1"><td>C</td><td>mousedown </td><td>100</td><td>-</td></tr><trid="mdn2"><td>D</td><td>mousedown using requestAnimationFrame</td><td>100</td><td>-</td></tr><trid="mmv1"><td>E</td><td>mousemove </td><td>100</td><td>-</td></tr><trid="mmv2"><td>F</td><td>mousemove using requestAnimationFrame</td><td>100</td><td>-</td></tr><trid="mup" ><td>G</td><td>mouseup </td><td>100</td><td>-</td></tr><trid="cmb1"><td>H</td><td>mousedown/move combo </td><td>100</td><td>-</td></tr><trid="cmb2"><td>I</td><td>mousedown/move/up combo </td><td>100</td><td>-</td></tr></table><inputtype="range"min="100"max="999"value="100"/><ol><li>The 'range value' column shows the value of the 'value' attribute of the range-type input, i.e. the slider. The 'random update indicator' column shows random text as an indicator of whether events are being actively fired and handled.</li><li>To see browser differences between input and change event implementations, use the slider in different browsers and compare A and B.</li><li>To see the importance of 'requestAnimationFrame' on 'mousedown', click a new location on the slider and compare C (incorrect) and D (correct).</li><li>To see the importance of 'requestAnimationFrame' on 'mousemove', click and drag but do not release the slider, and compare E (often 1 pixel behind) and F (correct).</li><li>To see why an initial mousedown is required (i.e. to see why mousemove alone is insufficient), click and hold but do not drag the slider and compare E (incorrect), F (incorrect) and H (correct).</li><li>To see how the mouse event combinations can provide a work-around for continuous update of a range-type input, use the slider in any manner and note whichever of A or B continuously updates the range value in your current browser. Then, while still using the slider, note that H and I provide the same continuously updated range value readings as A or B.</li><li>To see how the mouseup event reduces unnecessary calculations in the work-around, use the slider in any manner and compare H and I. They both provide correct range value readings. However, then ensure the mouse is released (i.e. not clicked) and move it over the slider without clicking and notice the ongoing updates in the third table column for H but not I.</li></ol>
- Andrew Willems
4
非常好的信息。也许有时候可以添加触摸事件?touchmove 应该足够了,我认为在这种情况下它可以像 mousemove 一样处理。 - nick
@nick,请查看本页面上我的另一个答案,其中提供了可以提供移动浏览器功能的不同解决方案。 - Andrew Willems
1这不是一个可访问的答案,因为键盘导航不会触发所有基于鼠标的事件。 - LocalPCGuy
@LocalPCGuy,你说得对。我的答案破坏了滑块的内置键盘可控性。我已经更新了代码以恢复键盘控制。如果你知道我的代码破坏了其他内置辅助功能的方式,请告诉我。 - Andrew Willems
更新2:对安德鲁2016年6月2日更新的答案做出回应:
谢谢,安德鲁 - 这似乎在我找到的所有浏览器中都有效(Win桌面:IE,Chrome,Opera,FF;Android Chrome,Opera和FF,iOS Safari)。
更新3:"oninput in slider"解决方案
以下内容似乎适用于上述所有浏览器。(我现在找不到原始来源了。)我曾经使用过这个,但后来在IE上失败了,所以我去寻找了另一个,因此我来到了这里。
if ("oninput"in slider1) {
slider1.addEventListener("input", function () {
// do whatever;
}, false);
}
但在我检查您的解决方案之前,我注意到在IE中此问题已经得到了解决 - 可能存在其他冲突。
- MBourne
2
2我确认你的解决方案在两个不同的桌面浏览器上都能正常工作:Mac Firefox和Windows IE11。我个人还没有能够检查任何移动设备的可能性。但这看起来像是对我的答案的一个很好的更新,它扩大了它的适用范围,包括移动设备。(我假设“输入”和“更改”在桌面系统上接受鼠标输入,在移动系统上接受触摸输入。)非常好的工作,应该广泛适用,并值得获得认可和实施! - Andrew Willems
1经过进一步的研究,我意识到您的解决方案存在几个缺点。首先,我认为requestAnimationFrame是不必要的。其次,该代码会触发额外的事件(例如,在某些浏览器中,mouseup至少会触发3个事件)。第三,不同浏览器之间触发的确切事件不同。因此,我提供了一个单独的答案,基于您最初使用“input”和“change”事件的想法,并给予您原始灵感的荣誉。 - Andrew Willems
我将此作为答案发布,以防您像我一样无法弄清楚为什么范围类型输入在任何移动浏览器上都不起作用。如果您在笔记本电脑上开发移动应用程序并使用响应模式来模拟触摸,则会注意到当您激活触摸模拟器时,范围根本不会移动。只有在停用它后才开始移动。我试了两天,尝试了我能找到的所有相关代码,但始终无法使其正常工作。在这篇文章中,我提供了一个可行的解决方案。 移动浏览器和混合应用程序 移动浏览器使用称为Webkit for iOS和WebView for Android的组件运行。 WebView / WebKit使您能够嵌入Web浏览器,该浏览器没有任何Chrome或Firefox(浏览器)控件,包括窗口框架,菜单,工具栏和滚动条,可以将其嵌入到您的活动布局中。换句话说,移动浏览器缺少许多通常在常规浏览器中找到的Web组件。这就是范围类型输入的问题所在。如果用户的浏览器不支持范围类型,则会回退并将其视为文本输入。这就是为什么您无法在激活触摸模拟器时移动范围的原因。
functionsetRangeValueChangeHandler(rangeElement, handler) {
rangeElement.oninput = (event) => {
handler(event);
// Save flag that we are using onInput in current browser
event.target.onInputHasBeenCalled = true;
};
rangeElement.onchange = (event) => {
// Call only if we are not using onInput in current browserif (!event.target.onInputHasBeenCalled) {
handler(event);
}
};
}
onchange
事件也不会触发。正是通过解决这个问题,我才找到了这个问题的答案。 - Sildoreth