Ao tentar resolver isso por mim mesmo, percebi que é realmente possível manter a rolagem da página e o foco da entrada enquanto desativa as alterações de número tentando disparar novamente o evento capturado no elemento pai do <input type="number"/>
no qual foi capturado , simplesmente assim:
e.target.parentElement.dispatchEvent(e);
No entanto, isso causa um erro no console do navegador e provavelmente não é garantido que funcione em todos os lugares (eu só testei no Firefox), pois é um código intencionalmente inválido.
Outra solução que funciona bem pelo menos no Firefox e no Chromium é fazer temporariamente o <input>
elemento readOnly
, assim:
function handleScroll(e) {
if (e.target.tagName.toLowerCase() === 'input'
&& (e.target.type === 'number')
&& (e.target === document.activeElement)
&& !e.target.readOnly
) {
e.target.readOnly = true;
setTimeout(function(el){ el.readOnly = false; }, 0, e.target);
}
}
document.addEventListener('wheel', function(e){ handleScroll(e); });
Um efeito colateral que observei é que pode fazer com que o campo pisque por uma fração de segundo se você tiver estilos diferentes para os readOnly
campos, mas, pelo menos no meu caso, isso não parece ser um problema.
Da mesma forma, (conforme explicado na resposta de James), em vez de modificar a readOnly
propriedade, você pode blur()
inserir o campo e depois focus()
voltar, mas, novamente, dependendo dos estilos em uso, pode ocorrer alguma oscilação.
Como alternativa, conforme mencionado em outros comentários aqui, você pode simplesmente ligar preventDefault()
para o evento. Supondo que você apenas manipule wheel
eventos em entradas de número que estão em foco e sob o cursor do mouse (é isso que as três condições acima significam), o impacto negativo na experiência do usuário seria quase nulo.