上输入类型onchange事件=范围并不在Firefox触发拖动时上输入类型onchange事件=范

2019-05-08 18:19发布

当我与播放<input type="range">火狐触发只有当我们下降滑块到新的位置,其中铬和其他触发事件电平变化而滑块被拖动的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;
}

Answer 1:

显然,Chrome和Safari都错了: onchange应该只被触发,当用户释放鼠标。 要获得持续的更新,你应该使用oninput事件,这将捕获在Firefox,Safari和Chrome实时更新,无论是从鼠标和键盘。

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

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

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



Answer 2:

摘要:

我在这里提供始终如一地范围/滑块互动,东西不可能在当前的浏览器响应无jQuery的跨浏览器的桌面和移动能力。 它实质上迫使所有浏览器效仿IE11的on("change"...事件无论他们on("change"...on("input"...的事件。新的功能...

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. 初始鼠标按下(或触摸开始)在新的滑块位置
  3. 任何后续的鼠标(或触摸)的运动沿着滑块1或2之后
  4. 任何后续的鼠标(或触摸)的运动的滑块1或2过去任一端后
  5. 最终鼠标向上(或触摸结束)

下表显示了至少三个不同的桌面浏览器在它们相对于行为,其中上述情况,他们回应的区别:

解:

所述onRangeChange功能提供了一个一致和可预测的跨浏览器响应于范围/滑块的相互作用。 它迫使所有浏览器根据下表的行为:

在IE11中,代码基本上可以让一切都按照现状进行操作,即它允许"change"事件在其标准的方式运作,并在"input"事件是无关紧要的,因为它从来没有火灾反正。 在其他浏览器中, "change"事件被有效沉默(防止燃烧多余的,有时不是,易视事件)。 此外, "input"事件触发它的听众只有当范围/滑块值发生变化。 对于某些浏览器(例如Firefox)的这种情况发生时,因为收听者在场景1中,4和5从上面的列表有效沉默。

(如果你真的需要一个监听器,在任何情况下1,4和/或5被激活,你可以尝试结合"mousedown" / "touchstart""mousemove" / "touchmove"和/或"mouseup" / "touchend"事件。这样的解决方案是超出了本答复的范围。)

功能在移动浏览器:

我已经在桌面浏览器,但没有在任何移动浏览器测试此代码。 然而,在此页面上的其他答案 MBourne表明,在这里我的解决方案” ......出现在每一个浏览器工作,我能找到的(赢桌面:IE浏览器,铬,歌剧,FF; Android的浏览器,Opera和FF,Safari浏览器的iOS) “。 (感谢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,行A和C中的场景2二者的变化和3的上方,而B行从不改变的值。
  • 在铬和Safari,行B和C的值在场景2二者的变化和3,而行A仅用于方案5的改变。
  • 在Firefox,在A行的值只对场景5的变化,对于所有五个场景B行的变化,并且仅用于方案2和3列C的变化。
  • 在所有上述的浏览器,在列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的输入类型范围滑块事件改变输入浏览器兼容性跨浏览器的桌面移动无jQuery的



Answer 3:

更新:我在这里离开这个答案如何使用鼠标事件使用在桌面上(而不是手机)的浏览器范围/滑块相互作用的例子。 不过,我现在还写了一个完全不同的,我相信,更好地回答别处此页面使用不同的方法来提供一个跨浏览器桌面- 移动解决这一问题上。

原来的答案:

提要:A跨浏览器,普通的JavaScript(即无jQuery的)溶液中,使读出范围的输入值,而无需使用on('input'...和/或on('change'... ,其浏览器之间不一致工作。

截至今日(二月下旬,2016),还有浏览器的不一致,所以我在这里提供一个新的变通。

问题:当使用一定范围的输入,即滑块, on('input'...提供不断更新的Mac和Windows的Firefox,Chrome和Opera以及Safari浏览器的Mac范围值,而on('change'...只报告在鼠标向上的范围值。与此相反,在Internet Explorer(V11), on('input'...不会在所有的工作,并on('change'...不断更新。

我在这里报告2个策略通过使用鼠标按下,鼠标移动和(可能)鼠标松开事件得到使用香草JavaScript的所有浏览器相同的连续范围值报告(即没有jQuery的)。

策略1:短,但效率较低

如果您在更高效的代码更喜欢短代码,你可以使用它使用mousesdown和鼠标移动而不是鼠标松开这1解决方案。 这读作必要的滑块,但继续在任何鼠标悬停事件不必要的射击,即使用户没有点击,因此没有拖动滑块。 它本质上同时读取后,“鼠标按下”,并在“鼠标移动”事件,稍微延迟每个使用范围值requestAnimationFrame

 var rng = document.querySelector("input"); read("mousedown"); read("mousemove"); read("keydown"); // include this to also allow keyboard control function read(evtType) { rng.addEventListener(evtType, function() { window.requestAnimationFrame(function () { document.querySelector("div").innerHTML = rng.value; rng.setAttribute("aria-valuenow", rng.value); // include for accessibility }); }); } 
 <div>50</div><input type="range"/> 

策略2:较长,但更高效

如果您需要更高效的代码,并可以容忍更长的码长,那么你可以使用下面的解决方案,它使用鼠标按下,鼠标移动和鼠标松开。 这也读滑块作为必要的,但适当地停止只要鼠标按钮被释放读它。 本质的区别是只启动监听“鼠标按下”后“鼠标移动”,并停止监听“鼠标松开”之后“鼠标移动”。

 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); 
 <div>50</div><input type="range"/> 

演示:对需要更充分的说明,以及实施的,上述的变通办法

下面的代码更充分体现了这一战略的许多方面。 说明被嵌入在演示:

 var select, inp, listen, unlisten, anim, show, onInp, onChg, onDn1, onDn2, onMv1, onMv2, onUp, onMvCombo1, onDnCombo1, onUpCombo2, onMvCombo2, onDnCombo2; select = function(selctr) { return document.querySelector(selctr); }; inp = select("input"); listen = function(evtTyp, cb) { return inp. addEventListener(evtTyp, cb); }; unlisten = function(evtTyp, cb) { return inp.removeEventListener(evtTyp, cb); }; anim = function(cb) { return window.requestAnimationFrame(cb); }; show = function(id) { return function() { select("#" + id + " td~td~td" ).innerHTML = inp.value; select("#" + id + " td~td~td~td").innerHTML = (Math.random() * 1e20).toString(36); // random text }; }; onInp = show("inp" ) ; onChg = show("chg" ) ; onDn1 = show("mdn1") ; onDn2 = function() {anim(show("mdn2")); }; onMv1 = show("mmv1") ; onMv2 = function() {anim(show("mmv2")); }; onUp = show("mup" ) ; onMvCombo1 = function() {anim(show("cmb1")); }; onDnCombo1 = function() {anim(show("cmb1")); listen("mousemove", onMvCombo1);}; onUpCombo2 = function() { unlisten("mousemove", onMvCombo2);}; onMvCombo2 = function() {anim(show("cmb2")); }; onDnCombo2 = function() {anim(show("cmb2")); listen("mousemove", onMvCombo2);}; listen("input" , onInp ); listen("change" , onChg ); listen("mousedown", onDn1 ); listen("mousedown", onDn2 ); listen("mousemove", onMv1 ); listen("mousemove", onMv2 ); listen("mouseup" , onUp ); listen("mousedown", onDnCombo1); listen("mousedown", onDnCombo2); listen("mouseup" , onUpCombo2); 
 table {border-collapse: collapse; font: 10pt Courier;} th, td {border: solid black 1px; padding: 0 0.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> <tr id="inp" ><td>A</td><td>input </td><td>100</td><td>-</td></tr> <tr id="chg" ><td>B</td><td>change </td><td>100</td><td>-</td></tr> <tr id="mdn1"><td>C</td><td>mousedown </td><td>100</td><td>-</td></tr> <tr id="mdn2"><td>D</td><td>mousedown using requestAnimationFrame</td><td>100</td><td>-</td></tr> <tr id="mmv1"><td>E</td><td>mousemove </td><td>100</td><td>-</td></tr> <tr id="mmv2"><td>F</td><td>mousemove using requestAnimationFrame</td><td>100</td><td>-</td></tr> <tr id="mup" ><td>G</td><td>mouseup </td><td>100</td><td>-</td></tr> <tr id="cmb1"><td>H</td><td>mousedown/move combo </td><td>100</td><td>-</td></tr> <tr id="cmb2"><td>I</td><td>mousedown/move/up combo </td><td>100</td><td>-</td></tr> </table> <input type="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, ie 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&nbsp;B.</li> <li>To see the importance of 'requestAnimationFrame' on 'mousedown', click a new location on the slider and compare C&nbsp;(incorrect) and D&nbsp;(correct).</li> <li>To see the importance of 'requestAnimationFrame' on 'mousemove', click and drag but do not release the slider, and compare E&nbsp;(often 1&nbsp;pixel behind) and F&nbsp;(correct).</li> <li>To see why an initial mousedown is required (ie to see why mousemove alone is insufficient), click and hold but do not drag the slider and compare E&nbsp;(incorrect), F&nbsp;(incorrect) and H&nbsp;(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&nbsp;I. They both provide correct range value readings. However, then ensure the mouse is released (ie not clicked) and move it over the slider without clicking and notice the ongoing updates in the third table column for H but not&nbsp;I.</li> </ol> 



Answer 4:

我张贴这是一个答案,因为它不愧为它自己的答案,而不是下一个用处不大的答案评论。 我觉得这个方法比接受的答案,因为它可以让所有的JS从HTML一个单独的文件要好得多。

答接受的答案下他的评论被Jamrelian提供。

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

要知道由Jaime此评论的,虽然

只要注意与此解决方案,在镀铬你会得到两次调用处理器(每个事件之一),因此,如果您关心的是,那么你就需要警惕了。

正如它会触发事件时,你已停止移动鼠标,然后再次当您松开鼠标按钮。



Answer 5:

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

下面是在边工作,IE,歌剧,FF,铬,iOS版Safari浏览器和移动当量(即我可以测试),他的第二个解决方案的修改:

更新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日更新的答案:

谢谢,安德鲁 - 这似乎是每一个浏览器我能找到工作,(赢桌面:IE浏览器,铬,歌剧,FF; Android的浏览器,Opera和FF,Safari浏览器的iOS)。

更新3:如果(“oninput在滑块)溶液

下面将出现在所有上述浏览器。 (我现在无法找到原始来源。)我是用这个,但终告失败的IE浏览器,所以我去寻找一个不同的,所以我在这里结束了。

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

但在此之前我检查你的解决方案,我发现这是在IE中再次合作 - 也许有一些其他冲突。



Answer 6:

对于良好的跨浏览器的行为,不太明白的代码,最好是使用onchange属性在窗体的组合:

这是一个html / JavaScript的唯一的解决方案,并且可以以及在线使用。

 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> 



Answer 7:

另一种方法 - 刚刚成立是哪个事件的类型应该被处理的元素信号标志:

function setRangeValueChangeHandler(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 browser
        if (!event.target.onInputHasBeenCalled) {
            handler(event);
        }
    };
}


Answer 8:

你可以使用JavaScript“ondrag当”活动,不断激发。 它比“输入”由于以下原因,更好:

  1. 浏览器支持。

  2. “ondrag当”和“改变”事件之间可以分化。 “输入”大火两个阻力和变化。

在jQuery的:

$('#sample').on('drag',function(e){

});

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



文章来源: onchange event on input type=range is not triggering in firefox while dragging