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

如何在Firefox中进行拖拽?

function showVal(newVal){ document.getElementById(“valBox”).innerHTML=newVal; } <span id=“valBox”></span> <输入类型=“范围” min=“5” max=“10” step=“1” onchange=“showVal(this.value)”>


当前回答

简介:

我在这里提供了一种无需jquery的跨浏览器桌面和移动设备的能力,以一致地响应范围/滑动条交互,这在当前的浏览器中是不可能的。它本质上迫使所有浏览器模仿IE11的on(“change”…事件为他们的on(“change”…或(“输入”……事件。新功能是…

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函数为范围/滑块交互提供了一致且可预测的跨浏览器响应。它迫使所有浏览器按照下表的方式运行:

In IE11, the code essentially allows everything to operate as per the status quo, i.e. it allows the "change" event to function in its standard way and the "input" event is irrelevant as it never fires anyway. In other browsers, the "change" event is effectively silenced (to prevent extra and sometimes not-readily-apparent events from firing). In addition, the "input" event fires its listener only when the range/slider's value changes. For some browsers (e.g. Firefox) this occurs because the listener is effectively silenced in scenarios 1, 4 and 5 from the above list.

(如果你真的需要在场景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() {...

or

var myListener = function(evt) {...

(从输入元素中删除事件监听器(例如使用removeEventListener)没有在这个答案中解决。)

演示说明:

在下面的代码片段中,onRangeChange函数提供了通用的解决方案。代码的其余部分只是一个示例,用于演示它的使用。任何以my开头的变量…与通用解决方案无关,只是为了演示而呈现。

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

在IE11中,场景2和场景3中,A行和C行值都发生变化,而B行值不变。 在Chrome浏览器和Safari浏览器中,场景2和场景3中B行和C行值都发生变化,场景5中A行值只发生变化。 在Firefox浏览器中,只有场景5中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

其他回答

显然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线程以获得更多信息。

简介:

我在这里提供了一种无需jquery的跨浏览器桌面和移动设备的能力,以一致地响应范围/滑动条交互,这在当前的浏览器中是不可能的。它本质上迫使所有浏览器模仿IE11的on(“change”…事件为他们的on(“change”…或(“输入”……事件。新功能是…

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函数为范围/滑块交互提供了一致且可预测的跨浏览器响应。它迫使所有浏览器按照下表的方式运行:

In IE11, the code essentially allows everything to operate as per the status quo, i.e. it allows the "change" event to function in its standard way and the "input" event is irrelevant as it never fires anyway. In other browsers, the "change" event is effectively silenced (to prevent extra and sometimes not-readily-apparent events from firing). In addition, the "input" event fires its listener only when the range/slider's value changes. For some browsers (e.g. Firefox) this occurs because the listener is effectively silenced in scenarios 1, 4 and 5 from the above list.

(如果你真的需要在场景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() {...

or

var myListener = function(evt) {...

(从输入元素中删除事件监听器(例如使用removeEventListener)没有在这个答案中解决。)

演示说明:

在下面的代码片段中,onRangeChange函数提供了通用的解决方案。代码的其余部分只是一个示例,用于演示它的使用。任何以my开头的变量…与通用解决方案无关,只是为了演示而呈现。

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

在IE11中,场景2和场景3中,A行和C行值都发生变化,而B行值不变。 在Chrome浏览器和Safari浏览器中,场景2和场景3中B行和C行值都发生变化,场景5中A行值只发生变化。 在Firefox浏览器中,只有场景5中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

还有另一种方法——在元素上设置一个标志,表明应该处理哪种类型的事件:

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);
        }
    };
}

你可以使用JavaScript的"ondrag"事件来连续触发。它优于“输入”,原因如下:

浏览器的支持。 可以区分“ondrag”和“change”事件。“输入”触发拖拽和更改。

jQuery:

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

});

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

我把这个作为一个答案,因为它应该是它自己的答案,而不是一个不那么有用的答案下的评论。我发现这种方法比公认的答案要好得多,因为它可以将所有的js与HTML保存在一个单独的文件中。

由Jamrelian在他的评论中提供的答案。

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

不过要注意Jaime的这句话

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

它会在你停止移动鼠标时触发事件,然后在你释放鼠标按钮时再次触发事件。

更新

对于导致功能两次触发的更改事件和输入事件,这几乎不是问题。

如果函数在输入时触发,则在触发change事件时不太可能出现问题。

当你拖动范围输入滑块时,输入会迅速触发。担心最后再触发一个函数调用,就像担心输入事件中的一滴水。

甚至包括更改事件的原因是为了浏览器兼容性(主要是IE)。