inputtypes= range的onchange事件在拖动时不会在firefox中触发

当我使用<input type="range"> ,只有当我们拖动滑块到Chrome和其他人在拖动滑块时触发onchange事件的新位置时,Firefox才会触发onchange事件。

我怎样才能使拖放在Firefox中发生?

HTML

 <span id="valBox"></span> <input type="range" min="5" max="10" step="1" onchange="showVal(this.value)"> 

脚本

 function showVal(newVal){ document.getElementById("valBox").innerHTML=newVal; } 

显然Chrome和Safari是错误的: onchange只能在用户释放鼠标时触发。 要获得持续的更新,您应该使用oninput事件,它将从Firefox,Safari和Chrome中捕获鼠标和键盘上的实时更新。

但是,IE10不支持oninput ,所以最好的办法就是把两个事件处理程序结合起来,像这样:

 <span id="valBox"></span> <input type="range" min="5" max="10" step="1" oninput="showVal(this.value)" onchange="showVal(this.value)"> 

看看这个Bugzilla线程获取更多信息。

更新:我在这里留下这个答案作为如何使用鼠标事件在桌面(而不是移动)浏览器中使用范围/滑块交互的示例。 不过,我现在也写了一个完全不同的,我相信,在这个页面的其他地方更好的回答 ,使用不同的方法来提供一个跨浏览器的桌面和移动解决scheme,以解决这个问题。

原始答案:

简介:一个跨浏览器,普通的JavaScript(即no-jQuery)解决scheme,允许读取范围input值,而不使用on('input'...和/或on('change'...之间的工作浏览器之间不一致。

截至今天(2016年2月下旬),浏览器仍然存在不一致,所以我在这里提供了一个新的解决方法。

问题:当使用范围input,即滑块, on('input'...提供不断更新的范围值在Mac和Windows的Firefox,Chrome和Opera以及Mac Safari的,而on('change'...只在鼠标移动时报告范围值,而在Internet Explorer(v11)中, on('input'...根本不起作用,并且on('change'...不断更新。

我在这里报告了两种策略,通过使用mousedown,mousemove和(可能的)mouseup事件,在所有浏览器中使用vanilla JavaScript(即没有jQuery)获得相同的连续范围值报告。

策略1:更短但效率更低

如果您更喜欢短代码而不是更高效的代码,则可以使用使用mousesdown和mousemove而不是mouseup的第一个解决scheme。 这将根据需要读取滑块,但是在任何鼠标hover事件期间,即使用户没有点击并因此不拖动滑块,也会不必要地继续触发。 它实质上在'mousedown'和'mousemove'事件之间读取范围值,稍微延迟每个使用requestAnimationFrame

 var rng = document.querySelector("input"); read("mousedown"); read("mousemove"); function read(evtType) { rng.addEventListener(evtType, function() { window.requestAnimationFrame(function () { document.querySelector("div").innerHTML = rng.value; }); }); } 
 <div>50</div><input type="range"/> 

我发布这个答案,因为它应该是自己的答案,而不是在一个不太有用的答案下的评论。 我发现这个方法比接受的答案好得多,因为它可以把所有的js保存在一个独立于HTML的文件中。

Jamrelian在他接受的答案下的评论中提供了答案。

 $("#myelement").on("input change", function() { //do something }); 

只要知道Jaime的这个评论

只要注意,在这个解决scheme中,在chrome中,你会得到两个调用处理程序(每个事件一个),所以如果你关心这个,那么你需要防范它。

因为它会在你停止移动鼠标时触发事件,然后当你释放鼠标button时再次触发事件。

概要:

我在这里提供了一个非jQuery跨浏览器的桌面和移动能力来始终如一地响应范围/滑块交互,这在当前的浏览器中是不可能的。 它基本上强制所有的浏览器模拟IE11的on("change"...事件为他们on("change"...on("input"...事件。新的function是…

 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是您的范围input元素, f是您的听众。 在任何改变范围/滑块值的交互之后,监听器将被调用,但是在不改变该值的交互之后(包括在当前滑块位置的初始鼠标或触摸交互或者移动滑块的任一端)之后不会被调用。

问题:

截至2016年6月初,不同的浏览器在响应范围/滑条使用方面有所不同。 五个情景是相关的:

  1. 在当前滑块位置初始鼠标向下(或触摸开始)
  2. 在新的滑块位置初始鼠标按下(或触摸开始)
  3. 沿滑块1或2之后的任何后续鼠标(或触摸)移动
  4. 在滑块两端1或2之后的任何后续鼠标(或触摸)移动
  5. 最后一次鼠标移动(或触摸结束)

下表显示了至less三个不同的桌面浏览器在其行为方面与上述哪个scheme有所不同:

表显示了浏览器与他们响应和何时发生的事件之间的差异

解:

onRangeChange函数为范围/滑块交互提供了一致且可预测的跨浏览器响应。 它强制所有浏览器按照下表进行操作:

表格显示使用建议的解决方案的所有浏览器的行为

在IE11中,代码基本上允许一切按照现状进行操作,即允许"change"事件以其标准方式工作,而"input"事件无关紧要,因为它永远不会触发。 在其他浏览器中, "change"事件被有效地阻止(以防止多余的,有时不太明显的事件被触发)。 另外,只有当范围/滑块的值改变时, "input"事件才会触发它的监听器。 对于某些浏览器(例如Firefox),会发生这种情况,因为在上面的列表中,情景1,4和5中的听众是有效的沉默的。

(如果您确实需要在情景1,情景4和/或情景5中激活侦听器,则可以尝试合并"mousedown" / "touchstart""mousemove" / "touchmove"和/或"mouseup" / "touchend"事件这样的解决scheme超出了这个答案的范围。)

移动浏览器的function:

我已经在桌面浏览器中testing过这个代码,但是在任何移动浏览器中都没有。 (Win桌面:IE,Chrome,Opera,FF; Android Chrome,Opera和FF,iOS Safari) “ 。 (感谢MBourne。)

用法:

要使用此解决scheme,请在您自己的代码中包含上述摘要(简化/缩小)中的onRangeChange函数或下面的演示代码片段(function相同但更明显)。 调用它如下:

 onRangeChange(myRangeInputElmt, myListener); 

其中myRangeInputElmt是您所需的<input type="range"> DOM元素,而myListener是您希望在"change"事件时调用的侦听器/处理程序函数。

如果需要,您的监听器可能无参数,或者可能使用event参数,即根据您的需要,可以使用以下任一项:

 var myListener = function() {... 

要么

 var myListener = function(evt) {... 

(从input元素中删除事件侦听removeEventListener (例如,使用removeEventListener )不在这个答案中。)

演示说明:

在下面的代码片段中, onRangeChange函数提供了通用的解决scheme。 其余的代码只是一个例子来演示它的使用。 任何以my...为开头的variables都与通用解决scheme无关,只是为演示而存在。

该演示显示范围/滑块值以及标准的"change""input"和自定义的"onRangeChange"事件触发(分别为行A,B和C)的次数。 在不同浏览器中运行此代码段时,请在与范围/滑块进行交互时注意以下事项:

  • 在IE11中,行A和行C中的值都在上面的情况2和3中改变,而行B从不改变。
  • 在Chrome和Safari中,行B和行C中的值都在scheme2和3中更改,而行A仅在scheme5中更改。
  • 在Firefox中,行A中的值仅在scheme5中更改,行B在所有五种scheme中都发生更改,行C仅在scheme2和3中发生更改。
  • 在所有上述浏览器中,行C(所提出的解决scheme)中的变化是相同的,即仅用于情况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> 

安德鲁威廉的解决scheme不是移动设备兼容。

这是他在Edge,IE,Opera,FF,Chrome,iOS Safari和移动等价物(我可以testing)中工作的第二个解决scheme的修改:

更新1:删除“requestAnimationFrame”部分,因为我同意这是没有必要的:

 var listener = function() { // do whatever }; slider1.addEventListener("input", function() { listener(); slider1.addEventListener("change", listener); }); slider1.addEventListener("change", function() { listener(); slider1.removeEventListener("input", listener); }); 

更新2:响应安德鲁的2016年6月2日更新回答:

谢谢安德鲁 – 这似乎在我能find的每个浏览器(Win桌面:IE,Chrome,Opera,FF; Android Chrome,Opera和FF,iOS Safari)都能正常工作。

更新3:if(“在滑块上input”)解决scheme

以下内容似乎适用于所有上述浏览器。 (我现在找不到原始资源)。我正在使用这个,但后来在IE上失败了,于是我去找另外一个,于是我就到了这里。

 if ("oninput" in slider1) { slider1.addEventListener("input", function () { // do whatever; }, false); } 

但是在我检查你的解决scheme之前,我注意到IE在再次运行 – 也许还有一些冲突。

对于一个良好的跨浏览器行为,较less和可以理解的代码,最好是使用onchange属性结合一个表单:

这是一个html / javascript唯一的解决scheme,也可以在线使用。

 function showVal(){ document.getElementById("valBox").innerHTML=document.getElementById("inVal").value; } 
 <form onchange="showVal()"> <input type="range" min="5" max="10" step="1" id="inVal"> </form> <span id="valBox"> </span> 

你可以使用JavaScript的“ondrag”事件不断的发射。 由于以下原因,比“投入”要好,

  1. 浏览器支持,
  2. 可以区分“ondrag”和“change”事件。 “input”既拖动又改变。

在jQuery中:

  $( '#样品')。在( '拖拽',函数(E){

 }); 

参考: http : //www.w3schools.com/TAgs/ev_ondrag.asp