使用鼠标滚轮增加输入值

3
我正在尝试使用鼠标滚轮增加/减少输入框的值。我已经编写了以下代码,它可以正常工作,但存在一个小问题。
我希望的行为是,一旦我聚焦到该元素上,就能够使用鼠标滚轮递增/递减输入值。鼠标不必悬停在该元素上。以下代码可以实现这一点。但如果我在悬停在输入元素上时使用滚轮,则值会递增/递减2而不是1。

var hoveredInput = null;

$('input[type="number"]').on("focus", function(e) {
  hoveredInput = this;
});
$('input[type="number"]').on("blur", function(e) {
  hoveredInput = null;
});

$(window).on("wheel", function(e) {
  if (hoveredInput) {
    if (e.originalEvent.deltaY < 0) {
      var currentValue = parseInt(hoveredInput.value, 10);
      var newValue = currentValue + 1;
      if (newValue > parseInt(hoveredInput.max, 10)) {
        newValue = hoveredInput.max;
      }
      hoveredInput.value = newValue;
    } else {
      var currentValue = parseInt(hoveredInput.value, 10);
      var newValue = currentValue - 1;
      if (newValue < parseInt(hoveredInput.min, 10)) {
        newValue = hoveredInput.min;
      }
      hoveredInput.value = newValue;
    }
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="number" value="0" min="0" max="255" />

经过一些试验,我发现上下箭头键有相似的行为。 在数字输入上,上下箭头键会增加/减少值。 我想,这种行为与我的代码冲突。 这导致它增加了2,即使代码没有执行两次。
我刚意识到这可能是Chrome特有的问题。如果您聚焦并悬停在元素上,Chrome允许您使用鼠标滚轮增加/减少数字输入值。然而,它的工作方式非常奇怪。
如果我只在一个空HTML页面中添加<input type="number" />,则此鼠标滚轮增量不起作用。要使其起作用,我只需添加window.onwheel = function() {};。这毫无意义。此外,在JSFiddle和JSBin上似乎可以正常工作,而不需要在window上分配onwheel
回到实际问题,我能否禁用元素上的默认鼠标滚轮增量,以便我可以使用自定义增量?或者是否有其他方法可以使用?
1个回答

3
我不确定为什么您会考虑不使用 preventDefault() 来阻止默认操作。这会改变在这些情况下 UI 操作的行为。您应该当然要使用 preventDefault() 来防止默认操作。如果您不使用 preventDefault(),那么当焦点在 <input type="number"> 上时滚动鼠标滚轮将会导致一些意想不到的后果。如果没有 preventDefault(),则在这些情况下会发生哪些意外后果将取决于用于查看页面的浏览器。
我无法重复使用光标键更改输入值时出现的冲突。显然,如果您仅使用鼠标滚轮的代码来限制 <input> 的最小和最大值,则这些限制将不适用于任何其他输入方法。您可以使用 minmax 属性来限制值。这样做有多个好处,包括它影响所有输入值的方法,并且允许针对每个 <input> 定义这些范围,而不是一组用于所有 <input type="number"> 的限制。我已更改代码,使您的代码也使用这些属性。
如果这样做,您可能希望考虑添加 CSS 样式以指示 <input type="number"> 元素已获得焦点。这样做将使用户更清楚地了解为什么鼠标滚轮不像他们通常从浏览器 UI 中期望的那样工作。
我建议您尝试在多个浏览器中进行测试,以查看是否需要此功能。就我个人而言,在我对此页面进行的测试中,我喜欢这种行为。
注意:您过度复杂地使用了 focusblur 事件。我已将代码更改为直接使用 document.activeElement 找到聚焦的元素。

//Exclude one specific element for comparing this UI vs. the browser's default.
var excludedEl = document.getElementById('exclude');

$(window).on("wheel", function(e) {
  focusedEl = document.activeElement;
  if(focusedEl === excludedEl){
    //Exclude one specific element for UI comparison 
    return;
  }
  if (focusedEl.nodeName='input' && focusedEl.type && focusedEl.type.match(/number/i)){
    e.preventDefault();
    var max=null;
    var min=null;
    if(focusedEl.hasAttribute('max')){
      max = focusedEl.getAttribute('max');
    }
    if(focusedEl.hasAttribute('min')){
      min = focusedEl.getAttribute('min');
    }
    var value = parseInt(focusedEl.value, 10);
    if (e.originalEvent.deltaY < 0) {
      value++;
      if (max !== null && value > max) {
        value = max;
      }
    } else {
      value--;
      if (min !== null && value < min) {
        value = min;
      }
    }
    focusedEl.value = value;
  }
});
input[type="number"]:focus {
  box-shadow: 0px 0px 1.5px 1px cyan;
}

/*For comparing UIs: May conflict with browser default, or user's theme.*/
#exclude:focus {
  box-shadow: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
NOTE: Events are only caught while the mouse stays within the test portion of the stackoverflow page:<br/><br/><br/>

Uses changed UI (if focused, mouse wheel will increment/decrement):<br/>
<input type="number" value="0" id="firstNumberInput" min="0" max="255"/>
<br/>Uses browser default UI:
<input id="exclude" type="number" value="0" min="0" max="255" style="display:block"/>


这真是我太傻了,竟然没想到使用 preventDefault()。而且我也不知道 document.activeElement。我还有另一个监听器来处理输入的最小值和最大值限制。只是因为它与手头的问题没有真正关系,所以我不想包含它。 - akinuri

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