禁止在`<input type = number>`上滚动


121

是否可以禁用滚轮在输入数字字段中更改数字?我已经弄乱了特定于Webkit的CSS,以删除微调框,但我想完全摆脱这种行为。我喜欢使用type=number它,因为它在iOS上带来了不错的键盘。


7
使用输入类型tel(type =“ tel”)代替使用type = number。它将弹出一个iOS num键盘。
Praveen Vijayan 2012年

当添加一个onscroll处理程序时,会发生event.preventDefault()什么?
罗伯茨2012年

14
以我的拙见,我什至不认为这应该是一个功能。如果我在浏览器开发方面有发言权,我可能会力推删除此功能。无非是烦人,我不知道有人会真正使用它。
柯克兰2014年

3
我完全同意你柯克兰。用表单滚动页面真是糟糕的UX,当数字输入元素进入鼠标下方时,它开始递增,页面停止滚动。完全迷失方向。
2014年

3
@PraveenVijayan:尽管这是一种解决方法,但它与使用新的html5输入类型的任何原因背道而驰。将来,电话可能会给您提供从联系人或其他任何东西中选择号码的可能性,如果您要指定的是另一种号码,这将非常奇怪。
2015年

Answers:


92

防止其他对象建议的输入数字元素上的mousewheel事件的默认行为(调用“ blur()”通常不是首选方法,因为这不是用户想要的)。

但。我会避免一直监听所有input-number元素上的mousewheel事件,而只在该元素处于焦点时(即存在问题的时候)才这样做。否则当鼠标指针位于输入数字元素上的任意位置时,用户将无法滚动页面

jQuery解决方案:

// disable mousewheel on a input number field when in focus
// (to prevent Cromium 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

很好的答案,但是至少在webkit中,这还可以防止在光标位于输入元素上方时窗口滚动。我认为鼠标滚轮事件也应该冒泡。
瑞安·麦克杰里

仅在焦点对准元素时将禁用滚动功能应用于该元素时,当鼠标悬停在输入元素上方时,这不应阻止滚动。但是,当元素处于焦点位置时,它可以防止滚动窗口。是的,为什么mousewheel事件不冒泡...:/
mousewheel

6
这是对一开始就不应该存在的行为的很好的修正。
强尼

这在大多数unix类型的平台gnome,osx,android(使用鼠标)上不起作用,因为滚动行为不需要集中输入。另外,我只使用了输入的文本类型并对其设置了数字限制(丢失了上/下键快捷键,但也可以与js一起添加)
zeachco


20

一个事件监听器可以全部统治

这类似于@Simon Perepelitsa在纯js中的回答,但有点简单,因为它将一个事件侦听器放在document元素上,并检查被关注元素是否为数字输入:

document.addEventListener("wheel", function(event){
    if(document.activeElement.type === "number"){
        document.activeElement.blur();
    }
});

如果要关闭某些字段上的值滚动行为,但不关闭其他字段,请执行以下操作:

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测试


我看到这已经被否决了。如果您发现问题,请与downvote一起发表评论。如果我错过了一些东西,我想学习它是什么。谢谢。
Peter Rakmanyi

1
对于现代浏览器,请使用event wheel而不是mousewheel。参考:developer.mozilla.org/zh-CN/docs/Web/API/Element/wheel_event PS。我不是投反对票的人。
VEE

19
input = document.getElementById("the_number_input")
input.addEventListener("mousewheel", function(event){ this.blur() })

http://jsfiddle.net/bQbDm/2/

对于jQuery示例和跨浏览器解决方案,请参见相关问题:

用于数字输入滚动的HTML5事件监听器-仅Chrome


2
感谢Seymon,我设法用jQuery来完成所有数字输入:$(':input[type=number]' ).live('mousewheel',function(e){ $(this).blur(); });我使用了模糊而不是阻止默认值,因此它不会阻止页面滚动!
Thibaut Colson

关于模糊的不错补充,我不知道您仍然可以允许页面滚动。我已经更新了答案。
Simon Perepelitsa

13
仅供参考,live()已弃用。现在,您应该使用on()$(':input[type=number]').on('mousewheel',function(e){ $(this).blur(); });
Saeid Zebardast 2013年

3
@SaeidZebardast您的评论值得一个答案
卑鄙的

对于现代浏览器,请使用event wheel而不是mousewheel。参考:developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event
vee

16

您可以简单地使用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中完美工作-材料6
Nasiruddin Saiyed '18


我们可以在许多资源中找到此CSS。无论如何,CSS只是一个奖励。真正的解决方案是HTML onwheel属性。;-)
Maikon Matheus

5
我喜欢这个解决方案!谢谢。就我而言,这onBlur()不是预期的。我设置了一个简单的方法return false来真正地“不做任何事情”。 <input type="number" onwheel="return false;">
丹尼尔(Daniel)

14

@Semyon Perepelitsa

有一个更好的解决方案。模糊将焦点从输入中移开,这是您不需要的副作用。您应该改用evt.preventDefault。这样可以防止用户滚动时输入的默认行为。这是代码:

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

6
它可以工作,但是事件不会冒泡,因此页面不会滚动。有没有办法保持默认行为(页面滚动)而不模糊?
GuiGS 2014年

对于现代浏览器,请使用event wheel而不是mousewheel。参考:developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event
vee

7

首先,您必须通过以下任一方式停止mousewheel事件:

  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');在模糊之前进行一次测试,以查看元素是否具有焦点:然后进行保护,仅在hadFocs为true时设置超时。
罗布·道森

2

提供的答案在Firefox(Quantum)中不起作用。需要将事件监听器从鼠标滚轮更改为滚轮:

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

此代码可在Firefox Quantum和Chrome上运行。


2

对于任何使用React并寻求解决方案的人。我发现最简单的方法是在Input组件中使用onWheelCapture道具,如下所示:

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


2

打字稿变化

Typescript需要知道您正在使用HTMLElement来确保类型安全,否则您将看到很多Property 'type' does not exist on type 'Element'类型的错误。

document.addEventListener("mousewheel", function(event){
  let numberInput = (<HTMLInputElement>document.activeElement);
  if (numberInput.type === "number") {
    numberInput.blur();
  }
});

1

在试图解决这个我自己,我注意到,它实际上可以保留页面输入的滚动和焦点,而试图通过重新火已捕获事件的父元素上禁用数量的变化<input type="number"/>上,它被抓获,就像这样:

e.target.parentElement.dispatchEvent(e);

但是,这会导致浏览器控制台出错,并且可能无法保证在所有地方都能正常工作(我仅在Firefox上进行了测试),因为它是有意的无效代码。

至少在Firefox和Chromium上很好用的另一个解决方案是临时制作<input>element readOnly,如下所示:

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

我注意到的一个副作用是,如果您对readOnly字段具有不同的样式,则可能会导致字段短暂闪烁,但是至少就我而言,这似乎不是问题。

同样,(如James的回答所述)readOnly您可以修改blur()字段,然后再将focus()其返回,而不是修改属性,但是同样,根据使用的样式,可能会出现一些闪烁。

另外,如此处其他评论所述,您可以preventDefault()改为调用该事件。假设您只处理wheel焦点在鼠标光标下方的数字输入上的事件(这是上面三个条件所表示的意思),那么对用户体验的负面影响将几乎没有。


1

如果您需要不需要JavaScript的解决方案,则可以将一些HTML功能与CSS伪元素结合使用,可以达到以下目的:

span {
  position: relative;
  display: inline-block; /* Fit around contents */
}

span::after {
  content: "";
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0; /* Stretch over containing block */
  cursor: text; /* restore I-beam cursor */
}

/* Restore context menu while editing */
input:focus {
  position: relative;
  z-index: 1;
}
<label>How many javascripts can u fit in u mouth?
  <span><input type="number" min="0" max="99" value="1"></span>
</label>

之所以有效,是因为点击了 <label>与表单字段相关联将使该字段集中。但是,该字段上的伪元素的“窗口窗格”将阻止鼠标滚轮事件到达它。

缺点是向上/向下微调器按钮不再起作用,但是您说您已经删除了那些按钮。


从理论上讲,可以还原上下文菜单而无需首先关注输入内容:用户滚动时不应触发:hover样式,因为出于性能方面的考虑,浏览器会避免在滚动过程中重新计算样式,但我尚未彻底跨浏览器/设备测试了。


0
function fixNumericScrolling() {
$$( "input[type=number]" ).addEvent( "mousewheel", function(e) {
    stopAll(e);     
} );
}

function stopAll(e) {
if( typeof( e.preventDefault               ) != "undefined" ) e.preventDefault();
if( typeof( e.stopImmediatePropagation     ) != "undefined" ) e.stopImmediatePropagation();
if( typeof( event ) != "undefined" ) {
    if( typeof( event.preventDefault           ) != "undefined" ) event.preventDefault();
    if( typeof( event.stopImmediatePropagation ) != "undefined" ) event.stopImmediatePropagation();
}

return false;
}

0

最简单的解决方案是添加onWheel={ event => event.currentTarget.blur() }}输入本身。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.