NumberInput mouse wheel handling ignores capture phase event filtering
P粉318928159
P粉318928159 2024-04-05 12:21:04
0
1
1596

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:

  • User scrolls mouse wheel
  • It’s JavaScript’s turn to handle the event
    • JavaScript performs capture/bubble operation
    • Event handlers can mark events as handled (preventDefault())
  • Outside JavaScript: If the event handler in JavaScript does not call PreventDefault(), the "user agent" will take its turn to handle the event. Since there is no fine-grained control over this, this step can only be completely stopped or continued. Since the "default handling" of number editing is changing the number value, the number changes and no scroll event is emitted.

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粉318928159
P粉318928159

reply all(1)
P粉262073176

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

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template