【问题标题】:Disable scrolling on `<input type=number>`在 `<input type=number>` 上禁用滚动
【发布时间】:2023-03-28 21:18:02
【问题描述】:

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

【问题讨论】:

  • 使用输入类型 tel (type="tel") 而不是使用 type=number。它会弹出一个 iOS 数字键盘。
  • 当你添加一个只包含event.preventDefault()onscroll 处理程序时会发生什么?
  • 以我的拙见,我什至认为这不应该是一个功能。如果我在浏览器开发中有任何发言权,我可能会推动删除此功能。它只是烦人,我不知道有谁会真正使用它。
  • 我完全同意柯克兰的观点。使用表单滚动页面只是糟糕的用户体验,当数字输入元素进入鼠标下方时,它开始增加并且页面停止滚动。完全迷失方向。
  • @PraveenVijayan:尽管这是一种解决方法,但它与使用新的 html5 输入类型的任何理由背道而驰。将来,手机可能会让您从联系人或任何东西中选择号码,如果您打算将其用作不同类型的号码,这看起来会很奇怪。

标签: javascript css html forms


【解决方案1】:
input = document.getElementById("the_number_input")
input.addEventListener("mousewheel", function(event){ this.blur() })

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

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

HTML5 event listener for number input scroll - Chrome only

【讨论】:

  • 感谢 Seymon,我设法通过这种方式使用 jQuery 输入所有数字:$(':input[type=number]' ).live('mousewheel',function(e){ $(this).blur(); }); 我使用模糊而不是阻止默认值,因此它不会阻止页面滚动!
  • 关于模糊的很好的补充,我不知道你仍然可以允许页面滚动。我已经更新了我的答案。
  • 仅供参考,live() 已弃用。现在,你应该使用on()$(':input[type=number]').on('mousewheel',function(e){ $(this).blur(); });
  • @SaeidZebardast 你的评论值得回答
  • 对于现代浏览器,请使用事件wheel 而不是mousewheel。参考:developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event
【解决方案2】:

@Semyon Perepelitsa

对此有更好的解决方案。 Blur 从输入中移除焦点,这是您不想要的副作用。您应该改用 evt.preventDefault。这可以防止用户滚动时输入的默认行为。代码如下:

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

【讨论】:

【解决方案3】:

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

但是。我会避免一直监听所有 input-number 元素上的鼠标滚轮事件,并且只在元素处于焦点时(即问题存在时)才这样做。否则当鼠标指针位于 input-number 元素上方时,用户无法滚动页面

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

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

【讨论】:

  • 很好的答案。我想如果我今天这样做,我会使用 Modernizr.touch 有条件地在非触摸设备上应用事件侦听器。基本上是user2863715在下面说的。
  • 很好的答案,但至少在 webkit 中,这也防止了当光标在输入元素上时窗口滚动。我认为鼠标滚轮事件也应该冒泡。
  • 仅在元素处于焦点时将禁用滚动功能应用于元素时,当鼠标悬停在输入元素上时,这不应阻止滚动。但是当元素处于焦点时,它会阻止滚动窗口。是的,为什么鼠标滚轮事件没有冒泡......:/
  • 这是对原本不应该存在的行为的一个很好的修复。
  • 这在大多数 unix 类型平台 gnome、osx、android(带鼠标)上不起作用,因为滚动行为不需要聚焦输入。或者,我只是使用了文本类型的输入并对其进行了数字限制(丢失了上/下键快捷键,但也可以使用 js 添加)
【解决方案4】:

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

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

【讨论】:

  • 一个很好看的解决方案,但在测试中我发现这个解决方案有窃取焦点的副作用。我对此进行了调整:在模糊之前测试元素是否具有焦点:var hadFocus = el.is(':focus');,然后在 hadFocs 为真时设置超时。
【解决方案5】:
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;
}

【讨论】:

    【解决方案6】:

    一个事件监听器来统治它们

    这类似于纯 js 中的@Simon Perepelitsaanswer,但更简单一些,因为它在文档元素上放置了一个事件侦听器并检查焦点元素是否为数字输入:

    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 类,它不会在滚动时更改,否则一切都保持不变。

    Test here with JSFiddle

    【讨论】:

    • 我看到这被否决了。如果您发现问题,请留下评论以及不赞成票。如果我错过了什么,我想知道它是什么。谢谢。
    • 对于现代浏览器,请使用事件wheel 而不是mousewheel。参考:developer.mozilla.org/en-US/docs/Web/API/Element/wheel_eventPS。我不是投反对票的人。
    【解决方案7】:
    $(document).on("wheel", "input[type=number]", function (e) {
        $(this).blur();
    });
    

    【讨论】:

    • 这是完美的。
    • 运行良好。谢谢。
    • 如果您选择该项目然后滚动,这在 Google Chrome 上会失败。该值仍有少量变化。
    【解决方案8】:

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

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

    此代码适用于 Firefox Quantum 和 Chrome。

    【讨论】:

      【解决方案9】:

      您可以简单地使用 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;
      }
      &lt;input type="number" onwheel="this.blur()" /&gt;

      【讨论】:

      • 谢谢兄弟!!它在 Angular - Material 6 中完美运行
      • 我们可以在许多来源中找到这个 CSS。无论如何,CSS只是一个奖励。这个问题的真正解决方案是 HTML onwheel 属性。 ;-)
      • 我喜欢这个解决方案!谢谢。在我的情况下,onBlur() 没有达到预期。我设置了一个简单的return false,而不是真正“在车轮上什么也不做”。 &lt;input type="number" onwheel="return false;"&gt;
      【解决方案10】:

      适用于任何使用 React 并正在寻找解决方案的人。我发现最简单的方法是在 Input 组件中使用 onWheelCapture 属性,如下所示:

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

      【讨论】:

        【解决方案11】:

        在尝试为自己解决这个问题时,我注意到实际上可以保留页面的滚动和输入的焦点,同时通过尝试重新触发 @987654321 的父元素上的捕获事件来禁用数字更改被抓到的@,就这么简单:

        e.target.parentElement.dispatchEvent(e);
        

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

        另一个至少在 Firefox 和 Chromium 上运行良好的解决方案是临时将 &lt;input&gt; 元素设为 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 的回答中所解释),您可以修改 blur() 字段,然后将其返回 focus(),而不是修改 readOnly 属性,但同样,根据使用的样式,可能会出现一些闪烁.

        或者,正如此处其他 cmets 所述,您可以在事件中调用 preventDefault()。假设您只处理焦点和鼠标光标下的数字输入上的wheel 事件(这就是上面三个条件所表示的),对用户体验的负面影响几乎没有。

        【讨论】:

          【解决方案12】:

          打字稿变体

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

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

          【讨论】:

            【解决方案13】:

            如果您想要一个不需要 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>

            这是有效的,因为单击与表单字段关联的 &lt;label&gt; 的内容将聚焦该字段。但是,字段上方的伪元素的“窗格”会阻止鼠标滚轮事件到达它。

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


            理论上,无需首先关注输入即可恢复上下文菜单::hover 样式不应在用户滚动时触发,因为浏览器会避免在滚动期间重新计算它们以提高性能原因,但我没有对它进行彻底的跨浏览器/设备测试。

            【讨论】:

              【解决方案14】:

              最简单的解决方案是在输入本身上添加onWheel={ event =&gt; event.currentTarget.blur() }}

              【讨论】:

                【解决方案15】:

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

                为什么不这样做呢?

                &lt;input type="number" onwheel="return false;" /&gt;

                它非常简单直接,易于实现,而且没有我能想到的副作用。

                【讨论】:

                • onmousewheel="return false;" 对我来说按预期工作。
                • 这可行,但缺点是当将鼠标悬停在焦点数字输入上时滚动根本不起作用。
                • @mckeed 我不确定我是否理解。这不是本意吗? OP 希望防止滚动更改输入值。
                • 效果很好,除非向下滚动带有数字字段的页面并且鼠标恰好越过数字字段。它打断了滚动。 (仅用 FF 测试)
                • @MeSo2,这是一个很好的观点。更改本机浏览器行为是一个很大的缺点。老实说,最好只使用 type="text" Lol。
                【解决方案16】:

                即使光标没有悬停在数字元素上,大多数答案也会模糊数字元素;以下没有

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

                https://jsfiddle.net/s06puv3j/1/

                【讨论】:

                  【解决方案17】:

                  我一直在努力解决这个问题。所以,这篇文章和其他文章帮助我做到了这一点。我们需要在这里更改有关最佳答案的一些内容。所以为了禁用滚动,我们必须添加以下内容:

                  <script>
                  $(document).ready(function() {
                      $('input[type=number]').on('wheel',function(e){ $(this).blur(); }); 
                  });
                  </script>
                  

                  我们不使用“onwheel”,而是使用“wheel”:)

                  【讨论】:

                    【解决方案18】:

                    Antd / React + Typescript 答案

                        const myComponent = () => {
                          const inputRef: React.RefObject<HTMLInputElement> = createRef();
                          
                          return <Input
                             ref={inputRef}
                             type="number"
                             onWheel={(e) => {
                               if (inputRef && inputRef.current && inputRef.current.blur) {
                                 inputRef.current.blur();
                               }
                               e.preventDefault();
                              }}
                          />
                        }
                    

                    【讨论】:

                      【解决方案19】:

                      就我而言,我需要保持焦点并仍然应用滚动。上面的解决方案都不能处理这个问题,而且做模糊/聚焦对我来说有点生硬。

                      这会保持现有焦点并保持滚动。你知道......就像浏览器应该的那样。仅在 chrome 中进行了最低限度的测试,仅支持 Y 轴。

                      // you could make this target a specific input instead of document
                      document.addEventListener('wheel', event => {
                        if (!event.target) return;
                        const isNumberInput = event.target.nodeName === 'INPUT' && event.target.type === 'number';
                        const isFocused = event.target === document.activeElement;
                        if (isNumberInput && isFocused) {
                          // prevent stupid input change
                          event.preventDefault();
                          // since we're taking over scrolling, we want to make sure
                          // nothing else gets the event
                          event.stopPropagation();
                          // finally we reapply the scroll
                          applyScroll(event);
                        }
                      }, { passive: false });
                      
                      // this walks up the tree for event.target to find the first
                      // scrollable parent.  this is probably good enough for most situations.
                      const applyScroll = event => {
                        try {
                          // console.debug('attempting to reapply scroll. searching for scrollable container...');
                          let scrollContainer = event.target;
                          while (scrollContainer && scrollContainer !== document.body && !elementIsScrollable(scrollContainer)) {
                            scrollContainer = scrollContainer.parentElement;
                            // console.debug('\t-> container was not scrollable. checking parent', scrollContainer);
                          }
                          if (scrollContainer) {
                            // console.debug('scrollContainer container found. applying scroll', scrollContainer, event.deltaY);
                            scrollContainer.scrollBy({ top: event.deltaY });
                          }
                          else {
                            // console.debug('no scrollContainer found');
                          }
                        }
                        catch (err) {
                          console.info('failed to reapply scroll', err, event);
                        }
                      };
                      
                      const elementIsScrollable = element => {
                        const { scrollHeight = 0, offsetHeight = 0 } = element;
                        const scrollable = style.overflowY === 'auto' || style.overflowY === 'scroll';
                        return scrollable && scrollHeight > 0 && offsetHeight > 0 && element.scrollHeight > element.offsetHeight;
                      };
                      
                      

                      【讨论】:

                        【解决方案20】:

                        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
                          setTimeout(() => {
                            e.target.focus()
                          }, 0)
                        }
                        
                        return <input type="number" onWheel={numberInputOnWheelPreventChange}/>
                        

                        【讨论】:

                          猜你喜欢
                          • 2020-11-23
                          • 2015-06-16
                          • 2011-04-27
                          • 2014-02-08
                          • 2014-10-17
                          • 1970-01-01
                          • 2016-05-24
                          相关资源
                          最近更新 更多