禁用`<input type=number>`的滚动功能

217

如何禁用滚轮改变输入数字字段中的数字?我已经使用 Webkit 特有的 CSS 来移除微调按钮,但我想完全取消此行为。我喜欢使用 type=number,因为这会在 iOS 上带来一个漂亮的键盘。


8
使用输入类型为“tel”(type="tel")而不是使用type=number。这将弹出iOS数字键盘。 - Praveen Vijayan
1
当您添加一个只有 event.preventDefault()onscroll 处理程序时会发生什么? - robertc
49
在我个人的看法中,我认为这个功能本就不应该存在。如果我能在浏览器开发中有所发言权,我可能会争取删除这个功能。它只是一种令人厌烦的东西,我不知道有谁会真正使用它。 - Kirkland
9
我完全同意你的观点,Kirkland。当页面上有一个表单且鼠标下方有数字输入框时,鼠标滚动会导致数字输入框的值增加并且页面停止滚动,这只会让人感到不适应。 - kjs3
6
虽然这是一个解决方法,但它违背了使用新的HTML5输入类型的任何原因。未来可能会有手机提供从联系人中选择号码或其他内容的功能,如果您希望这是不同类型的号码,那么这将显得非常奇怪。 - awe
显示剩余2条评论
24个回答

146

防止像其他人建议的那样在输入数字元素上触发鼠标滚轮事件的默认行为(调用“blur()”通常不是首选方式,因为那不是用户想要的)。

但是,我建议只在元素处于焦点状态时侦听鼠标滚轮事件,而不是一直在所有输入数字元素上进行侦听(这是问题出现的情况)。否则当鼠标指针位于输入数字元素上方时,用户将无法滚动页面

jQuery解决方案:

// disable mousewheel on a input number field when in focus
// (to prevent Chromium browsers change the value when scrolling)
$('form').on('focus', 'input[type=number]', function (e) {
  $(this).on('wheel.disableScroll', function (e) {
    e.preventDefault()
  })
})
$('form').on('blur', 'input[type=number]', function (e) {
  $(this).off('wheel.disableScroll')
})

将焦点事件委托给周围的表单元素-以避免过多的事件监听器,这对性能不利。


2
很好的答案。我认为如果我今天要做这件事,我会使用Modernizr.touch在非触摸设备上有条件地应用事件监听器。基本上就是下面user2863715所说的。 - kjs3
21
这是一种不应存在于首位的行为的良好修复措施。 - Jonny
这在大多数Unix类型平台gnome、osx、android(带鼠标)上不起作用,因为滚动行为不需要输入聚焦。或者,我只是使用了文本输入类型,并将我的数字限制放在其中(失去了上/下键快捷方式,但也可以使用js添加)。 - zeachco
1
“wheel.disableScroll”事件是什么,它与“wheel”事件有何独特之处和不同之处?我在网上找不到关于此事件中“disableScroll”部分的信息。 - Art Geigel
1
我喜欢这个解决方案的概念,并将其移植到 MUI,供任何 React Js 开发人员使用。https://gist.github.com/jeff-r-koyaltech/786b4b31e632398ddc4dba948081c266 - undefined
显示剩余7条评论

88

一种事件监听器解决所有问题

这类似于@Simon Perepelitsa在纯JS中的答案,但更简单, 因为它在文档元素上放置了一个事件监听器,用于所有输入,并检查焦点元素是否为数字输入类型

document.addEventListener("wheel", function(event){
    if(document.activeElement.type === "number"){
        document.activeElement.blur();
    }
});
如果您希望关闭某些字段的值滚动行为(按类/ ID),而不关闭其他字段,则只需添加&&和相应的文档选择器即可:
document.addEventListener("wheel", function(event){
    if(document.activeElement.type === "number" &&
       document.activeElement.classList.contains("noscroll"))
    {
        document.activeElement.blur();
    }
});
以此为基础:
<input type="number" class="noscroll"/>
如果输入具有noscroll类,则在滚动时它不会改变,否则一切保持不变。

在JSFiddle中进行测试


1
我看到这个被踩了。如果您发现问题,请在踩的同时留下评论。如果我漏掉了什么,我想学习一下是什么。谢谢。 - Peter Rakmanyi
5
请使用事件 wheel 而不是 mousewheel,以适应现代浏览器。 参考:https://developer.mozilla.org/zh-CN/docs/Web/API/Element/wheel_eventPS. 我不是点踩的人。 - vee
这个问题的一个小问题是脚本将在每个元素的每个鼠标滚轮事件上运行。 如果由于某种原因存在一个不是输入的自定义元素,并且具有一个名为"number"的属性,它也会运行并导致难以调试的问题。 - wkrueger
@wkrueger "number"是指在<input type="number">中的输入类型,而不是在<custom number="some_value">中的属性。如果条件不满足,它会尽快退出。这个想法是为了避免有很多监听器,并且在元素动态添加和删除时也能正常工作。欢迎提出改进建议。 - Peter Rakmanyi

49
$(document).on("wheel", "input[type=number]", function (e) {
    $(this).blur();
});

3
这是完美的那一个。 - Patrik Laszlo
工作得很好。谢谢。 - Vijay S
1
如果您在Google Chrome中选择该项目然后滚动,此操作将失败。值仍会略微更改。 - eKKiM

38

您可以简单地使用HTML onwheel 属性。

这个选项对页面上其他元素的滚动没有影响。

为所有输入添加侦听器不适用于动态创建的输入。

此外,您可以使用CSS删除输入箭头。

input[type="number"]::-webkit-outer-spin-button, 
input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}
input[type="number"] {
    -moz-appearance: textfield;
}
<input type="number" onwheel="this.blur()" />


1
谢谢兄弟!! 它在Angular-Material 6中完美运行。 - Nasiruddin Saiyed
1
关闭数字输入微调器 - Hafiz Temuri
1
我们可以在许多来源中找到这个CSS。无论如何,CSS只是一个额外的奖励。对于这个问题的真正解决方案是HTML的onwheel属性。;-) - Maikon Matheus
6
我喜欢这个解决方案!谢谢。在我的情况下,“onBlur()”的效果不如预期。我改成了简单的“return false”来真正“在滚轮上什么也不做”。<input type="number" onwheel="return false;"> - Donni

24

我有一个替代方案。我认为大多数常见的建议是触发模糊事件,问题在于它具有意想不到的副作用。意外移除焦点状态并不总是好事。

为什么不使用这个呢?

<input type="number" onwheel="return false;" />

这非常简单且直接,易于实现,并且我可以想到没有任何副作用。


3
对我来说,onmousewheel="return false;" 的效果如预期一样。 - TPoschel
1
这个可以起到作用,但缺点是当鼠标悬停在一个聚焦的数字输入上时,滚动根本不起作用。 - mckeed
除了在滚动带有数字字段的页面并且鼠标碰巧经过数字字段时会中断滚动之外,它都运行良好。(仅在FF上测试过) - MeSo2
1
@MeSo2,这是一个很好的观点。改变本地浏览器行为是一个很大的缺点。说实话,只使用type="text"通常更好。 Lol。 - Austin Gil
7
对于React / Next.js,我使用了这个 onWheel={e => e.target.blur()}。我不确定为什么Mac没有提供禁用它的选项。 - Surjith S M
显示剩余2条评论

23

ReactJS解决方案

对于需要React解决方案的人,这是一个onWheel处理程序,用于您的type="number"输入,以防止数字更改并防止页面在用户尝试滚动输入时滚动。最后,它将重新聚焦于输入,以便用户可以按预期继续编辑:

const numberInputOnWheelPreventChange = (e) => {
  // Prevent the input value change
  e.target.blur()

  // Prevent the page/container scrolling
  e.stopPropagation()

  // Refocus immediately, on the next tick (after the current function is done)
  setTimeout(() => {
    e.target.focus()
  }, 0)
}

return <input type="number" onWheel={numberInputOnWheelPreventChange}/>

1
这似乎是最好的React解决方案,谢谢。 - Rayner
@TheodoreBrown 我认为用户在滚动输入时并不希望滚动整个页面。但这绝对是你的团队需要做出的用户体验选择。 - lwdthe1
如果用户滚动鼠标滚轮,我认为他们期望页面会滚动,就像光标悬停在不更改值的其他输入类型上时一样。 - Theodore Brown
@TheodoreBrown 当然可以,但我个人经历过相反的需求。这是一个应该被每个团队考虑的用户体验选择。对于你的用户来说,你不希望滚动。这并不意味着另一种选择是错误的。 - lwdthe1
1
这个可以。 - undefined
显示剩余2条评论

19

2
谢谢Seymon,我用jQuery成功地对所有数字输入进行了如下处理:$(':input[type=number]' ).live('mousewheel',function(e){ $(this).blur(); }); 我使用了blur而不是prevent default,这样就不会阻止页面滚动了! - Thibaut Colson
关于模糊效果的这个附加信息很好,我不知道你还可以允许页面滚动。我已经更新了我的答案。 - Simon Perepelitsa
13
FYI,“live()”已被弃用。现在,您应该使用“on()”:$(':input [type = number] ')。on('mousewheel',function(e){ $(this)。blur(); }); - Saeid
3
你的评论值得成为一个答案。 - snumpy
请使用事件wheel代替mousewheel,以适应现代浏览器。参考:https://developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event - vee

16

这个问题有更好的解决方案。 Blur 会移除输入框的焦点,但这不是你想要的副作用。相反,你应该使用 evt.preventDefault。这可以阻止用户滚动时输入框的默认行为。以下是代码:

input = document.getElementById("the_number_input")
input.addEventListener("mousewheel", function(evt){ evt.preventDefault(); })

9
可以正常工作,但事件不会冒泡,所以页面不会滚动。有没有一种方法可以保持默认行为(页面滚动),而不需要模糊处理? - GuiGS
1
请使用事件wheel代替mousewheel,以适应现代浏览器。参考:https://developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event - vee

15

对于任何正在使用React并需要解决此问题的人,我已经发现最简单的方法是在Input组件中使用onWheelCapture属性,就像这样:

onWheelCapture={e => { e.target.blur() }}


1
target没有blur(),所以我不得不使用e.currentTarget.blur()来使其工作。 - M. Lee

8

首先,你必须通过以下方式之一停止鼠标滚轮事件:

  1. 使用 mousewheel.disableScroll 来禁用它。
  2. 使用 e.preventDefault(); 拦截它。
  3. 使用 el.blur(); 将焦点从元素上移除。

前两种方法都会停止窗口滚动,而最后一种方法则会移除元素的焦点,这两种结果都是不希望出现的。

一个解决方法是在延迟后使用 el.blur() 并重新聚焦元素:

$('input[type=number]').on('mousewheel', function(){
  var el = $(this);
  el.blur();
  setTimeout(function(){
    el.focus();
  }, 10);
});

3
一种外观不错的解决方案,但在测试中我发现这个解决方案有一个副作用,会窃取焦点。我进行了调整: 在模糊之前添加了检查元素是否具有焦点的测试:var hadFocus = el.is(':focus');,然后加入一项保护措施,仅在hadFocus为true时设置超时。 - Rob Dawson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接