Home  >  Q&A  >  body text

NumberInput mouse wheel handling ignores capture phase event filtering

Very short version:

I'm a bit stuck and don't quite understand why this code does indeed intercept and prevent mouse wheel events from being interpreted by the number editor to change numbers. I'd like to understand why intercepting capture and filtering events doesn't work:

HTML code:

<p id="p-number-1">
  <input id="number-1" type="number" min="0" max="100" value="50" class="number-input">
</p>
<p id="log">
</p>

JavaScript code:

function log(m) {
  const logp = document.getElementById("log")
  logp.innerHTML += "" + m + "<br>";
}

log("Logging started")

const pnum1 = document.getElementById("p-number-1")
const num1 = document.getElementById("number-1")

pnum1.addEventListener("wheel", function(e) { 
    log("captured outer");
    e.stopPropagation();
}, true);

num1.addEventListener("wheel", function(e) { 
    log("bubble inner");
}, false);

num1.addEventListener("wheel", function(e) { 
    log("capture inner");
}, true);

function log(m) {
  const logp = document.getElementById("log")
  logp.innerHTML += "" + m + "<br>";
}

log("Logging started")

const pnum1 = document.getElementById("p-number-1")
const num1 = document.getElementById("number-1")

pnum1.addEventListener("wheel", function(e) { 
    log("captured outer");
    e.stopPropagation();
}, true);

num1.addEventListener("wheel", function(e) { 
    log("bubble inner");
}, false);

num1.addEventListener("wheel", function(e) { 
    log("capture inner");
}, true);

Instructions: Click on the entered number to focus it, then use the mouse wheel. The mouse wheel is intercepted by the JavaScript code, but even if I stop the propagation on the surrounding

during the capture phase, the numbers still change.

For your convenience: https://jsfiddle.net/Ljku4gha/6/

What do I want to achieve?

I want to write a reusable component using the default numeric input field (and actually a slider). I don't want the user to be able to use the scroll wheel on these inputs to change the numbers. Instead, the mousewheel should trigger events on some (unknown!) div (most likely) around it for scrolling purposes. So I want to prevent the number editor (and slider) from handling mouse wheel events in some way.

Longer Version: My Analysis/Hypothesis

I can't completelyexplain it, but there are two hypotheses for what's going on.

My first thought, and what I think is most likely, is that this is an artifact of how browsers handle user events (keyword "user agent" I think). However, if anyone could point out where I can read about how browsers handle user events, that would be very welcome. Until then, my understanding of event handling in browsers is as follows:

Result:*sad me*

However, I think this theory makes the most sense, but maybe it's completely wrong? !

Alternative boring explanation: Am I listening to the wrong event?

Maybe I'm missing something and the wheel events are converted to other events that I can block Default() on? I can't find any information about it, but it makes perfect sense to me... maybe? It's not even a "reel", that's all I can say.


I'd mainly like to get some guidance to help me understand why what I'm doing isn't working...and would welcome solutions as well!

P粉318928159P粉318928159155 days ago1352

reply all(1)I'll reply

  • P粉262073176

    P粉2620731762024-04-06 10:32:13

    Use event.preventDefault() to prevent the default behavior of numeric input.

    We have 2 improvements:

    • Prevent the scroll wheel only when the input is focused (when the wheel changes value). This way, when the input is unfocused, the scroll wheel will behave as normal
    • When the input is focused, prevents the default and blurs the input so that on the next wheel event scrolling will work again (you should decide if you want this adjustment).

    You can't solve this problem by capturing because

    Unfortunately when you capture the default behavior happens before the event bubbles up to the input

    Therefore stopPropagation() does not help during the capture phase.

    const p = document.getElementById("p-number-1")
    const num1 = document.getElementById("number-1")
    
    
    
    num1.addEventListener("wheel", function(e) { 
        console.log("input wheel");
        if(e.target.matches(':focus')){
          console.log("input wheel prevented");
          e.preventDefault();
          e.target.blur();
        }
    }, false);
    p{
      height:1000px;
    }
    input{
      pointer-events: none1;
    }

    reply
    0
  • Cancelreply