摘要:
我在这里提供了无jQuery跨浏览器的桌面和移动功能,能够始终如一地响应范围/滑块交互,这是当前浏览器无法实现的。实质上,它会强制所有浏览器on("change"...
为其on("change"...
或on("input"...
事件模拟IE11的事件。新功能是...
function onRangeChange(r,f) {
var n,c,m;
r.addEventListener("input",function(e){n=1;c=e.target.value;if(c!=m)f(e);m=c;});
r.addEventListener("change",function(e){if(!n)f(e);});
}
... r
您的范围输入元素在哪里,并且f
是您的监听器。在更改范围/滑块值的任何交互之后(而不是在不更改该值/滑块值的任何交互)之后(包括在当前滑块位置处的初始鼠标或触摸交互或从滑块任一端移开)之后,都不会调用侦听器。
问题:
截至2016年6月上旬,不同的浏览器对范围/滑块使用的反应方式有所不同。有五个场景是相关的:
- 在当前滑块位置初始按下鼠标(或触摸启动)
- 在新的滑杆位置进行初始的鼠标下移(或触摸启动)
- 沿滑块1或2之后的任何后续鼠标(或触摸)移动
- 经过滑块任一端1或2之后的任何后续鼠标(或触摸)移动
- 最后的鼠标上移(或触摸结束)
下表显示了至少三种不同的桌面浏览器在其响应上述哪种情况方面的行为不同:
解:
该onRangeChange
功能为范围/滑块交互提供了一致且可预测的跨浏览器响应。它将强制所有浏览器按照下表进行操作:
在IE11中,代码本质上允许所有事情都按现状运行,即,它允许"change"
事件以其标准方式起作用,并且该"input"
事件无关紧要,因为它永远不会触发。在其他浏览器中,该"change"
事件被有效地静音(以防止触发额外的,有时不是很明显的事件)。此外,"input"
仅当范围/滑块的值更改时,事件才会触发其侦听器。对于某些浏览器(例如Firefox),这是因为在上述列表中的情况1、4和5中,侦听器实际上已被静音。
(如果您确实需要在情况1、4和/或5中激活监听器,则可以尝试合并"mousedown"
/ "touchstart"
,"mousemove"
/ "touchmove"
和/或"mouseup"
/ "touchend"
事件。这样的解决方案不在此答案的范围内。)
移动浏览器中的功能:
我已经在台式机浏览器中测试了此代码,但未在任何移动浏览器中测试过此代码。但是,在此页面的另一个答案中, MBourne表明我的解决方案“ ...似乎可以在我能找到的每种浏览器中运行(Win桌面:IE,Chrome,Opera,FF; Android Chrome,Opera和FF,iOS Safari) “。(感谢MBourne。)
用法:
要使用此解决方案,请onRangeChange
在您自己的代码中包含上面摘要中的功能(简化/缩小)或下面的演示代码片段(功能相同,但更不言自明)。如下调用:
onRangeChange(myRangeInputElmt, myListener);
myRangeInputElmt
所需的<input type="range">
DOM元素在哪里,是您myListener
要在"change"
类似事件时调用的侦听器/处理函数。
如果需要,您的侦听器可以是无参数的,也可以使用该event
参数,即,根据您的需要,以下两种方法均可使用:
var myListener = function() {...
要么
var myListener = function(evt) {...
(在此答案中未解决从input
元素中删除事件监听器(例如使用removeEventListener
)。)
演示说明:
在下面的代码片段中,该函数onRangeChange
提供了通用解决方案。其余代码只是一个演示其用法的示例。开头的任何变量my...
都与通用解决方案无关,仅出于演示目的而存在。
演示显示的范围内/滑块值以及次标准数"change"
,"input"
和自定义"onRangeChange"
事件烧制(行分别为A,B和C)。在不同的浏览器中运行此代码段时,在与范围/滑块互动时请注意以下几点:
- 在IE11中,在上面的情况2和3中,行A和C的值都发生了变化,而行B则从不发生变化。
- 在Chrome和Safari中,场景2和3中的B行和C行中的值均发生变化,而场景5中的A行仅发生变化。
- 在Firefox中,行A的值仅针对方案5发生更改,行B的所有五个方案均发生变化,行C仅针对方案2和3发生变化。
- 在以上所有浏览器中,C行(建议的解决方案)中的更改都是相同的,即仅适用于方案2和3。
演示代码:
// main function for emulating IE11's "change" event:
function onRangeChange(rangeInputElmt, listener) {
var inputEvtHasNeverFired = true;
var rangeValue = {current: undefined, mostRecent: undefined};
rangeInputElmt.addEventListener("input", function(evt) {
inputEvtHasNeverFired = false;
rangeValue.current = evt.target.value;
if (rangeValue.current !== rangeValue.mostRecent) {
listener(evt);
}
rangeValue.mostRecent = rangeValue.current;
});
rangeInputElmt.addEventListener("change", function(evt) {
if (inputEvtHasNeverFired) {
listener(evt);
}
});
}
// example usage:
var myRangeInputElmt = document.querySelector("input" );
var myRangeValPar = document.querySelector("#rangeValPar" );
var myNumChgEvtsCell = document.querySelector("#numChgEvtsCell");
var myNumInpEvtsCell = document.querySelector("#numInpEvtsCell");
var myNumCusEvtsCell = document.querySelector("#numCusEvtsCell");
var myNumEvts = {input: 0, change: 0, custom: 0};
var myUpdate = function() {
myNumChgEvtsCell.innerHTML = myNumEvts["change"];
myNumInpEvtsCell.innerHTML = myNumEvts["input" ];
myNumCusEvtsCell.innerHTML = myNumEvts["custom"];
};
["input", "change"].forEach(function(myEvtType) {
myRangeInputElmt.addEventListener(myEvtType, function() {
myNumEvts[myEvtType] += 1;
myUpdate();
});
});
var myListener = function(myEvt) {
myNumEvts["custom"] += 1;
myRangeValPar.innerHTML = "range value: " + myEvt.target.value;
myUpdate();
};
onRangeChange(myRangeInputElmt, myListener);
table {
border-collapse: collapse;
}
th, td {
text-align: left;
border: solid black 1px;
padding: 5px 15px;
}
<input type="range"/>
<p id="rangeValPar">range value: 50</p>
<table>
<tr><th>row</th><th>event type </th><th>number of events </th><tr>
<tr><td>A</td><td>standard "change" events </td><td id="numChgEvtsCell">0</td></tr>
<tr><td>B</td><td>standard "input" events </td><td id="numInpEvtsCell">0</td></tr>
<tr><td>C</td><td>new custom "onRangeChange" events</td><td id="numCusEvtsCell">0</td></tr>
</table>
信用:
虽然这里的实现很大程度上是我自己的,但它受到MBourne的回答的启发。另一个答案表明可以将“输入”和“更改”事件合并,并且所产生的代码将在台式机和移动浏览器中均有效。但是,该答案中的代码导致触发了隐藏的“额外”事件,这本身就是有问题的,并且触发的事件在浏览器之间有所不同,这是另一个问题。我在这里的实现解决了这些问题。
关键字:
JavaScript输入类型范围滑块事件更改输入浏览器兼容性跨浏览器桌面移动No-jQuery
onchange
不会触发。正是在解决该问题的过程中,我才发现了这个问题。