O evento onchange no tipo de input = range não está sendo acionado no firefox enquanto arrasta

Quando eu joguei com , o Firefox aciona um evento onchange apenas se deixarmos o controle deslizante em uma nova posição onde o Chrome e outros acionam events onchange enquanto o controle deslizante é arrastado.

Como posso fazer isso ao arrastar no firefox?

HTML

   

ROTEIRO

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

    Aparentemente, o Chrome e o Safari estão errados: o onchange só deve ser acionado quando o usuário soltar o mouse. Para obter atualizações contínuas, você deve usar o evento oninput , que capturará atualizações ao vivo no Firefox, Safari e Chrome, tanto do mouse quanto do teclado.

    No entanto, oninput não é suportado no IE10, então sua melhor aposta é combinar os dois manipuladores de events, assim:

       

    Confira este tópico do Bugzilla para mais informações.

    ATUALIZAÇÃO: Estou deixando esta resposta aqui como um exemplo de como usar events de mouse para usar interações de intervalo / controle deslizante em navegadores de desktop (mas não em dispositivos móveis). No entanto, agora também escrevi uma resposta completamente diferente e, acredito, melhor em outro lugar nesta página que usa uma abordagem diferente para fornecer uma solução de desktop e móvel entre navegadores para esse problema.

    Resposta original:

    Resumo: Uma solução JavaScript cruzada (ou seja, não-jQuery) para permitir valores de input do intervalo de leitura sem usar on('input'... e / ou on('change'... que funcionam de forma inconsistente entre os navegadores.

    A partir de hoje (final de fevereiro de 2016), ainda há inconsistência do navegador, então estou oferecendo uma nova solução para esse problema aqui.

    O problema: Ao usar uma input de intervalo, ou seja, um controle deslizante, on('input'... fornece continuamente valores de intervalo atualizados no Mac e Windows Firefox, Chrome e Opera, bem como Mac Safari, enquanto on('change'... reporta apenas o valor do intervalo após o mouse-up Em contraste, no Internet Explorer (v11), on('input'... não funciona de todo e on('change'... é continuamente atualizado).

    Eu relato aqui duas estratégias para obter relatórios idênticos de valores de faixa contínuos em todos os navegadores usando JavaScript vanilla (ou seja, sem jQuery) usando os events mousedown, mousemove e (possivelmente) mouseup.

    Estratégia 1: Menor, mas menos eficiente

    Se você preferir um código mais curto em um código mais eficiente, poderá usar essa primeira solução que usa mousesdown e mousemove, mas não mouseup. Isso lê o controle deslizante conforme necessário, mas continua triggersndo desnecessariamente durante qualquer evento de passagem do mouse, mesmo quando o usuário não clicou e, portanto, não está arrastando o controle deslizante. Ele essencialmente lê o valor do intervalo após o ‘mousedown’ e durante os events ‘mousemove’, atrasando um pouco cada um usando 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 }); }); } 
     
    50

    Estou postando isso como uma resposta porque merece ser a sua própria resposta em vez de um comentário com uma resposta menos útil. Eu acho este método muito melhor do que a resposta aceita, uma vez que pode manter todos os js em um arquivo separado do HTML.

    Resposta fornecida por Jamrelian em seu comentário sob a resposta aceita.

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

    Basta estar ciente deste comentário por Jaime embora

    Apenas observe que com esta solução, no chrome você terá duas chamadas para o manipulador (uma por evento), então se você se importar com isso, então você precisa se proteger contra isso.

    Como ele irá triggersr o evento quando você parou de mover o mouse, e novamente quando você soltar o botão do mouse.

    RESUMO:

    Eu disponibilizo aqui uma capacidade de desktop e móvel sem navegador cruzado do jQuery para responder de forma consistente às interações intervalo / controle deslizante, algo que não é possível nos navegadores atuais. Isso basicamente força todos os navegadores a emular o evento on("change"... do IE11 para seus events on("change"... ou on("input"... . A nova 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);}); } 

    … onde r é o seu elemento de input de intervalo e f é o seu ouvinte. O ouvinte será chamado após qualquer interação que altere o valor do intervalo / controle deslizante, mas não após as interações que não alteram esse valor, incluindo as interações iniciais do mouse ou do toque na posição do controle deslizante atual ou ao finalizar o controle deslizante.

    Problema:

    No início de junho de 2016, diferentes navegadores diferem em termos de como eles respondem ao uso do intervalo / slider. Cinco cenários são relevantes:

    1. inicial do mouse para baixo (ou touch-start) na posição atual do controle deslizante
    2. inicial do mouse para baixo (ou touch-start) em uma nova posição de controle deslizante
    3. qualquer movimento subseqüente do mouse (ou toque) após 1 ou 2 ao longo do controle deslizante
    4. qualquer movimento subseqüente do mouse (ou toque) após 1 ou 2 passado de cada extremidade do controle deslizante
    5. mouse-up final (ou touch-end)

    A tabela a seguir mostra como pelo menos três diferentes navegadores de desktop diferem em seu comportamento em relação a quais dos cenários acima eles respondem:

    tabela mostrando as diferenças do navegador em relação a quais eventos eles respondem e quando

    Solução:

    A function onRangeChange fornece uma resposta consistente e previsível entre navegadores para interações de intervalo / controle deslizante. Força todos os navegadores a se comportarem de acordo com a seguinte tabela:

    tabela mostrando o comportamento de todos os navegadores usando a solução proposta

    No IE11, o código essencialmente permite que tudo funcione de acordo com o status quo, ou seja, permite que o evento "change" funcione de maneira padrão e o evento "input" é irrelevante, pois ele nunca é acionado de qualquer maneira. Em outros navegadores, o evento "change" é efetivamente silenciado (para evitar que events extras e às vezes não aparentes sejam triggersdos). Além disso, o evento "input" triggers seu ouvinte somente quando o valor do intervalo / controle deslizante é alterado. Para alguns navegadores (por exemplo, Firefox) isso ocorre porque o ouvinte é efetivamente silenciado nos cenários 1, 4 e 5 da lista acima.

    (Se você realmente precisar que um ouvinte seja ativado em qualquer um dos cenários 1, 4 e / ou 5, você pode tentar incorporar "mousedown" / "touchstart" , "mousemove" / "touchmove" e / ou "mouseup" / "touchend" Tal solução está além do escopo desta resposta.)

    Funcionalidade em navegadores móveis:

    Eu testei esse código em navegadores de desktop, mas não em navegadores móveis. No entanto, em outra resposta nesta página, MBourne mostrou que a minha solução aqui “… parece funcionar em todos os navegadores que encontrei (Win desktop: IE, Chrome, Opera, FF; Android Chrome, Opera e FF, iOS Safari) “ . (Obrigado MBourne.)

    Uso:

    Para usar essa solução, inclua a function onRangeChange do resumo acima (simplificado / minificado) ou o snippet do código de demonstração abaixo (funcionalmente idêntico, mas mais auto-explicativo) em seu próprio código. Invoque-o da seguinte maneira:

     onRangeChange(myRangeInputElmt, myListener); 

    onde myRangeInputElmt é o elemento DOM myListener e myListener é a function listener / handler que você deseja invocar em events "change" .

    Seu ouvinte pode ser sem parâmetro, se desejado, ou pode usar o parâmetro event , ou seja, qualquer um dos seguintes funcionaria, dependendo de suas necessidades:

     var myListener = function() {... 

    ou

     var myListener = function(evt) {... 

    (Remover o ouvinte de evento do elemento de input (por exemplo, usando removeEventListener ) não é abordado nesta resposta.)

    Descrição Demo:

    No trecho de código abaixo, a function onRangeChange fornece a solução universal. O resto do código é simplesmente um exemplo para demonstrar seu uso. Qualquer variável que comece com o my... é irrelevante para a solução universal e está presente apenas por causa da demonstração.

    A demonstração mostra o valor do intervalo / slider, bem como o número de vezes que os events padrão "change" , "input" e "onRangeChange" foram acionados (linhas A, B e C, respectivamente). Ao executar esse snippet em diferentes navegadores, observe o seguinte conforme você interage com o intervalo / controle deslizante:

    • No IE11, os valores nas linhas A e C mudam nos cenários 2 e 3 acima, enquanto a linha B nunca muda.
    • No Chrome e no Safari, os valores nas linhas B e C são alterados nos cenários 2 e 3, enquanto a linha A muda apenas para o cenário 5.
    • No Firefox, o valor na linha A muda apenas para o cenário 5, a linha B muda para todos os cinco cenários e a linha C muda apenas para os cenários 2 e 3.
    • Em todos os navegadores acima, as alterações na linha C (a solução proposta) são idênticas, ou seja, apenas para os cenários 2 e 3.

    Código Demo:

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

    range value: 50

    rowevent type number of events
    Astandard "change" events 0
    Bstandard "input" events 0
    Cnew custom "onRangeChange" events0

    As soluções de Andrew Willem não são compatíveis com dispositivos móveis.

    Aqui está uma modificação de sua segunda solução que funciona no Edge, IE, Opera, FF, Chrome, iOS Safari e equivalentes móveis (que eu pude testar):

    Atualização 1: parte “requestAnimationFrame” removida, pois concordo que não é necessário:

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

    Atualização 2: Resposta à resposta atualizada de Andrew em 2 de junho de 2016:

    Obrigado, Andrew – que parece funcionar em todos os navegadores que eu poderia encontrar (Win desktop: IE, Chrome, Opera, FF, Android Chrome, Opera e FF, iOS Safari).

    Atualização 3: se (“ininput em slider) solução

    O seguinte parece funcionar em todos os navegadores acima. (Eu não consigo encontrar a fonte original agora.) Eu estava usando isso, mas posteriormente falhou no IE e então eu fui procurar um diferente, daí acabei aqui.

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

    Mas antes de verificar sua solução, percebi que isso estava funcionando novamente no IE – talvez houvesse algum outro conflito.

    Para um bom comportamento entre navegadores, menos código compreensível, é melhor usar o atributo onchange em combinação de um formulário:

    Esta é apenas uma solução html / javascript, e também pode ser usada em linha.

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

    Você poderia usar o evento “ondrag” do JavaScript para triggersr continuamente. É melhor que “input” devido às seguintes razões:

    1. Suporte de navegador.

    2. Poderia diferenciar entre o evento “ondrag” e “change”. “input” é acionado tanto para arrastar quanto para alterar.

    Em jQuery:

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

    Referência: http://www.w3schools.com/TAgs/ev_ondrag.asp