禁用“ < input type = number >”上的滚动

是否可以禁用滚轮更改输入数字字段中的数字? 我已经修改了特定于 webkit 的 CSS 来删除 spinner,但是我想完全去除这种行为。我喜欢使用 type=number,因为它在 iOS 上带来了一个漂亮的键盘。

167592 次浏览
input = document.getElementById("the_number_input")
input.addEventListener("mousewheel", function(event){ this.blur() })

Http://jsfiddle.net/bqbdm/2/

有关 jQuery 的例子和跨浏览器解决方案,请参阅相关问题:

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

@ Semyon Perepelitsa

有一个更好的解决办法。红蓝侠从输入中移除焦点,这是您不希望出现的副作用。您应该改为使用 evt.proventDefault。这可以防止用户滚动时输入的默认行为。密码如下:

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

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

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

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

(将焦点事件委托给周围的 form 元素,以避免对许多事件侦听器造成不利的性能影响。)

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

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

一个事件侦听器来统治所有事件

这与 @ Simon Perepelitsa回答在纯 js 中类似,但更简单一些,因为它把 在文档元素上为所有输入设置一个事件侦听器,并检查所关注的元素是否为数字输入 tpye放在:

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

如果您想关闭 某些字段按类/id 排列,但其他字段不按类/id 排列上的值滚动行为,只需添加 &&和相应的文档选择器:

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

用这个:

<input type="number" class="noscroll"/>

如果一个输入具有 noroll 类,它不会在滚动中改变,否则一切都保持不变。

在这里用 JSFiddle 测试

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

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

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

这段代码可以在 Firefox Quantum 和 Chrome 上运行。

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

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

并且为所有的输入添加一个侦听器不能在后面动态创建的输入中工作。

此外,您还可以使用 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()" />

任何人与反应和寻找解决方案的工作。我发现最简单的方法是像下面这样在输入组件中使用 onWheelCapture 道具:

OnWheelCapture = { e = > { 目标,模糊() }}

当我试图自己解决这个问题时,我注意到实际上是可以保持页面的滚动和输入的焦点,同时禁用数字变化,方法是尝试在 <input type="number"/>的父元素上重新激活捕捉到的事件,就像这样:

e.target.parentElement.dispatchEvent(e);

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

另一个至少在 Firefox 和 Chromium 上运行良好的解决方案是临时使用 <input>元素 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事件(这是上述三个条件所表示的) ,那么对用户体验的负面影响几乎为零。

打字稿变体

类型脚本需要知道您使用 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();
}
});

如果您想要一个不需要 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样式 不应该在用户滚动时触发,因为浏览器出于性能原因在滚动时避免重新计算它们,但我还没有完全跨浏览器/设备测试它。

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

我有另一个建议。我发现大多数常见的触发模糊事件的建议存在的问题是,它具有意想不到的副作用。意外删除焦点状态并不总是好事。

为什么不用这个呢?

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

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

大多数答案模糊了数字元素,即使光标没有悬停在上面; 下面的答案没有

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/

我一直在想办法。所以,这个和其他的帖子帮助我做到这一点。关于这个问题的最佳答案,我们需要改变一些东西。因此,为了禁用滚动,我们必须添加以下内容:

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

我们用“车轮”代替“车轮”:)

和/反应 + 打字答案

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

在我的情况下,我需要保持焦点,仍然应用卷轴。以上所有的解决方案都不能解决这个问题,而且模糊/聚焦对我来说有点不合适。

这样既可以保持现有的焦点,也可以保持滚动。就像浏览器应该做的那样。只有最低限度的测试在铬和只支持 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;
};


ReactJS 解决方案

对于那些需要一个反应解决方案,这里有一个 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}/>

非 JS 解决方案

我喜欢使用 type = number,因为它在 iOS 上提供了一个不错的键盘。

键盘确实不错,但是我们可以通过以下方式获得同样的性能:

<input inputmode="numeric" pattern="[0-9]*" />

取自 Gov.uk,它在 MUI 文档中被链接。对于我们的产品工作得很好。

还有一点

请检查 浏览器支持 inputmode。大多数移动浏览器是支持的,对我来说 inputmode主要是关于移动体验。但是 YMMV。