【问题标题】:Detecting number input spinner click检测数字输入微调器点击
【发布时间】:2015-12-03 17:14:49
【问题描述】:

我有一个简单的数字输入,带有 min="1"max="12" 值集,用作小时选择器。我希望它在几个小时内循环,所以当您到达 12 并按“向上”箭头时,它会返回到 1,反之亦然。

现在我大部分时间都在工作:

var inputTimer = null;

function cycle(element) {
  if (element.attributes.max && element.attributes.min) {
    var prevVal = element.value;
    inputTimer = setTimeout(function() {
      if (prevVal === element.attributes.max.value) {
        element.value = element.attributes.min.value;
      } else if (prevVal === element.attributes.min.value) {
        element.value = element.attributes.max.value;
      }
    }, 50);
  }
}

$("input[type='number']")
  .on("mousedown", function(e) {
    //this event happens before the `input` event!
    cycle(this);
  }).on('keydown', function(e) {
    //up & down arrow keys
    //this event happens before the `input` event!
    if (e.keyCode === 38 || e.keyCode === 40) {
      cycle(this);
    }
  }).on('input', function(e) {
    //this event happens whenever the value changes
    clearTimeout(inputTimer);
  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="number" min="1" max="12" value="12" />

Working DEMO

我遇到的问题是,我找不到一种方法来检测输入中的箭头微调器是否已被单击,或者只是整个输入已被单击。现在它有一个问题,当您单击字段中的任意位置时,当值当前位于 112 时,它会更改值

有没有办法检测点击事件是否发生在文本字段中的微调器/箭头上?

【问题讨论】:

  • onchange 事件运行良好 jsfiddle.net/29bea3y0
  • @Ramanlfc 不,不是。我无法像上面的演示那样循环回到最小/最大值。
  • 也许这里的答案,关于如何获取鼠标坐标可以与你已有的结合使用:stackoverflow.com/questions/7790725/…
  • 我也看过使用 this.style.cursor,但它总是返回 "",和 $(this).css('cursor'),但它总是返回 "text",无论是不是你超过了向上/向下箭头。

标签: javascript html


【解决方案1】:

您必须像这样处理input 事件:

$('[type=number]').on('input',function(){
  this.value %= 12 ;
  if( this.value < 1 )
    this.value -= -12 ;
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type=number>

【讨论】:

  • 这不使用 min 和 max 属性,如果 min 设置为 1 和 max 设置为 12,则不会触发。
  • @MartinEyles,这只是硬编码最小值和最大值的示例。从其他任何地方获取这些数字很简单,比如元素的 minmax 属性。
  • @MartinEyles - 这是相同的答案,但引用元素的 minmax 值:&lt;input type=number value=1 min=1 max=12&gt;&lt;script&gt;var $i=$("[type=number]"),[m,M]=[$i.attr("min"),$i.attr("max")];$i.attr({min:m-1,max:M+1});$i.on("input",function(){this.value%=M;if(this.value&lt;m){this.value-=-M}});&lt;/script&gt;
【解决方案2】:

我搜索了很多,似乎没有无法在本地检测到。这使得这个问题成为一个非常重要的问题,因为我认为这应该添加到新版本的 HTML 中。

有许多可能的解决方法。他们都在无法知道价值走向何方的问题上失败了。我决定使用鼠标位置信息来检测用户是增加还是减少值。当用户按住按钮时,它可以工作,但不能正确处理这种情况。

var inputTimer = null;

function cycle(event) {
  var value = this.value;
  // Value deep within bonds -> no action
  if(value>this.min && value<this.max) {
    return;  
  }
  // Check coordinate of the mouse
  var x,y;
  //This is the current screen rectangle of input
  var rect = this.getBoundingClientRect();
  var width = rect.right - rect.left;
  var height = rect.bottom-rect.top;
  //Recalculate mouse offsets to relative offsets
  x = event.clientX - rect.left;
  y = event.clientY - rect.top;
  // Now let's say that we expect the click only in the last 80%
  // of the input
  if(x/width<0.8) {
    console.log("Not click on arrows.", x, width);  
    return;
  }
  // Check "clicked button" by checking how high on input was clicked
  var percentHeight = y/height;
  // Top arrow was clicked
  if(percentHeight<0.5 && value==this.max) {
      this.value = this.min; 
      event.preventDefault();
      return false;
  }
  // Bottom arrow was clicked
  if(percentHeight>0.5 && value==this.min) {
      this.value = this.max; 
      event.preventDefault();
      return false;
  }
}
var input = document.getElementById("number");
input.addEventListener("mousedown", cycle);
&lt;input id="number" type="number" min="1" max="12" value="12" /&gt;

【讨论】:

  • 在 safari OS X 中不起作用。在最小值和最大值处停止,而不返回到相反的范围值。
  • 这很尴尬。是否有任何错误或只是停止?我可以像你一样在 VM 中测试它,但我强烈暗示这是 Safari 做错了什么。
  • 控制台中没有错误。它只是停止了,但是有很多日志说Not click on arrows. 25 33 并且每次点击都会记录下来。在开始、范围之间或范围结束时以及当我单击向上和向下箭头时。
  • @AtheistP3ace 我希望我们能尽快从 W3C 获得官方解决方案,这些变通方法非常不令人满意。回家的路上我一直在想这件事(我在工作 4 小时前做出了这个答案),但没有想到其他任何事情。
  • 我同意。这个问题让我想了一整天。我什至在工作中与另一位开发人员谈论它。期望一个范围是循环的,这似乎不是一个古怪的想法。很惊讶它还没有启用它的属性。
【解决方案3】:

我认为这是你真正想要的。

<input type="time" value="01:00" step="600"/>

目前没有本地方法来捕获与输入框事件分开的箭头输入事件。为此目的,使用数字输入的所有内容似乎都有些 hacky。

下一个最佳选择类似于http://jdewit.github.io/bootstrap-timepicker/

【讨论】:

  • 看起来time 类型虽然受 IE、Firefox 或 Safari 支持 :( quirksmode.org/html5/inputs
  • 以上错字!那应该是“不支持”!
  • 通过 jQuery,您可以捕获“鼠标滚轮”事件,该事件涵盖了输入微调器操作。 A.g.:$("#InputID").on('change mousewheel', function() { ... }); 将在发生变化以及单击任何微调器按钮后触发(当然也包括鼠标滚轮动作)。通过 vanilla Javascript,您始终可以编写一个检查 e.type == "wheel" 的函数。我从未尝试过,但它应该可以工作。这里有更多关于如何实现事件检测的信息:stackoverflow.com/questions/25204282/…
  • 如果您想使用最重要的部分来表示无限的数字(例如 45 小时 10 分钟为 45:10),则不能使用时间输入类型。您仍然需要为此使用两个单独的数字输入。
【解决方案4】:

这不适用于您有最大值并希望将其换行的特定情况,但对于希望通过箭头根据更改处理字段值的其他人可能会有所帮助,例如设置.toFixed(2)到我需要的货币价值:

document.getElementById('el').setAttribute('data-last',document.getElementById('el').value);
document.getElementById('el').addEventListener('keyup', function(){
    this.setAttribute('data-last',this.value);
});
document.getElementById('el').addEventListener('click', function(){
    if(this.value>this.getAttribute('data-last')) console.log('up clicked');
    if(this.value<this.getAttribute('data-last')) console.log('down clicked');
});

【讨论】:

    【解决方案5】:

    这是我用JQuery写的代码,这个可以实现自动递增(+&-)长按旋转按钮。

    $.fn.spinInput = function (options) {
        var settings = $.extend({
            maximum: 1000,
            minimum: 0,
            value: 1,
            onChange: null
        }, options);
    
        return this.each(function (index, item) {
            var min = $(item).find('>*:first-child').first();
            var max = $(item).find('>*:last-child').first();
            var v_span = $(item).find('>*:nth-child(2)').find('span');
            var v_input = $(item).find('>*:nth-child(2)').find('input');
            var value = settings.value;
            $(v_input).val(value);
            $(v_span).text(value);
            async function increment() {
                value = Number.parseInt($(v_input).val());
                if ((value - 1) > settings.maximum) return;
                value++;
                $(v_input).val(value);
                $(v_span).text(value);
                if (settings.onChange) settings.onChange(value);
            }
            async function desincrement() {
                value = Number.parseInt($(v_input).val());
                if ((value - 1) < settings.minimum) return;
                value--
                $(v_input).val(value);
                $(v_span).text(value);
                if (settings.onChange) settings.onChange(value);
            }
            var pressTimer;
    
            function actionHandler(btn, fct, time = 100, ...args) {
                function longHandler() {
                    pressTimer = window.setTimeout(function () {
                        fct(...args);
                        clearTimeout(pressTimer);
                        longHandler()
                    }, time);
                }
                $(btn).mouseup(function () {
                    clearTimeout(pressTimer);
                }).mousedown(function () {
                    longHandler();
                });
    
                $(btn).click(function () {
                    fct(...args);
                });
            }
    
            actionHandler(min, desincrement, 100);
            actionHandler(max, increment, 100)
        })
    }
    
    
    
    
    $('body').ready(function () {
        $('.spin-input').spinInput({ value: 1, minimum: 1 });
    });
    :root {
        --primary-dark-color: #F3283C;
        --primary-light-color: #FF6978;
        --success-dark-color: #32A071;
        --sucess-light-color: #06E775;
        --alert-light-color: #a42a23;
        --alert-dark-color: #7a1f1a;
        --secondary-dark-color: #666666;
        --secondary-light-color: #A6A6A6;
        --gold-dark-color: #FFA500;
        --gold-light-color: #FFBD00;
        --default-dark-color: #1E2C31;
        --default-light-color: #E5E5E5;
    }
    
    .fx-row {
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;
    }
    
    .fx-colum {
        display: flex;
        flex-direction: column;
        flex-wrap: wrap;
    }
    
    .fx-colum.nowrap,
    .fx-row.nowrap {
        flex-wrap: nowrap;
    }
    
    .fx-row.fx-fill>*,
    .fx-colum.fx-fill>* {
        flex-grow: 1;
    }
    
    .spin-input {
        border: 1px solid var(--secondary-light-color);
    }
    
    .spin-input>div:first-child {
        cursor: pointer;
        border-right: 1px solid var(--secondary-light-color);
    }
    
    .spin-input>div:first-child:active {
        transform: translate3d(1px, 0px, 1px)
    }
    
    .spin-input>div:last-child {
        flex: none;
        border-left: 1px solid var(--secondary-light-color);
        cursor: pointer;
    }
    
    .spin-input>div:last-child:active {
        transform: translate3d(1px, 0px, 1px)
    }
    
    .icon {
        font-weight: bold;
        text-align: center;
        vertical-align: middle;
        padding: 12px;
        font-size: 28px;
    }
    
    .icon.primary,
    .icon.primary .ci {
        color: var(--primary-dark-color);
    }
    
    .icon.reactive:hover .ci {
        color: var(--primary-light-color);
    }
    
    .hidden {
        display: none;
    }
    <script src="https://releases.jquery.com/git/jquery-3.x-git.min.js"></script>
    <div class="spin-input nowrap fx-row fx-fill" >
                            <div class="icon reactive">
                                <span class="ci ci-minus">-</span>
                            </div>
                            <div class="icon">
                                <span>0</span>
                                <input type="text" class="hidden" value="0">
                            </div>
                            <div class="icon reactive">
                                <span class="ci ci-plus">+</span>
                            </div>
                        </div>

    有我的jQuery插件,希望对你有帮助。

    【讨论】:

      【解决方案6】:

      所以我不确定是否有任何方法可以确定被点击的内容,无论是字段输入还是小箭头,但我能够让它像这样工作。

      小提琴:http://jsfiddle.net/nusjua9s/4/

      JS:

      (function($) {
      
          var methods = {
              cycle: function() {
                  if (this.attributes.max && this.attributes.min) {
                      var val = this.value;
                      var min = parseInt(this.attributes.min.value, 10);
                      var max = parseInt(this.attributes.max.value, 10);
                      if (val === this.attributes.max.value) {
                          this.value = min + 1;
                      } else if (val === this.attributes.min.value) {
                          this.value = max - 1;
                      } else if (!(val > min && val < max)) {
                          // Handle values being typed in that are out of range
                          this.value = $(this).attr('data-default');
                      }
                  }
              }
          };
      
          $.fn.circularRange = function() {
              return this.each(function() {
                  if (this.attributes.max && this.attributes.min) {
                      var $this = $(this);
                      var defaultVal = this.value;
                      var min = parseInt(this.attributes.min.value, 10);
                      var max = parseInt(this.attributes.max.value, 10);
                      $this.attr('min', min - 1);
                      $this.attr('max', max + 1);
                      $this.attr('data-default', defaultVal);
                      $this.on("change", methods.cycle);
                  }
              });
          };
      
      })(jQuery);
      
      $("input[type='number']").circularRange();
      

      HTML:

      <input type="number" min="1" max="12" value="12" />
      

      所以我不知道为什么我一直在思考这个问题,但它仍然无法解决您看到的超出范围的数字闪烁问题,而我没有看到。但现在至少设置 html 范围并不令人困惑。您可以不假思索地设置您想要的范围,只需初始化type="number" 字段。

      【讨论】:

      • 嗯,对我来说它发生得太快了,我看不到它。 @TomášZato您的意思是您看到它从13切换到1?或者它允许你去 13?
      • 是的,我可以清楚地看到“0”和“13”短暂闪烁,这也涉及到很多数字的硬编码。我希望能够以通用方式重用此代码。
      • @ChrisBarr 更新了答案以删除硬编码数字。至于闪烁,我看不到。让我想想我是否能找到另一种方法。
      • @AtheistP3ace 没错,这不再对数字进行硬编码,但设置起来很混乱。您必须提前知道,如果您想要最大值为 12,则必须将其设置为 13。它确实有效,但它真的很奇怪,并且“超出范围”的值在 Windows 中的 Chrome 上会短暂闪烁.
      • 是的,我也真的不喜欢 jQuery,我只是这样做了,因为他说将数字设置为 +/-1 令人困惑,我看到他在他的问题中使用 jquery。我想我会留下答案。也许有一天它会帮助某人=]
      【解决方案7】:

      试试 $('input[type="number"]').change(function() {}); ?没有结果?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-05-21
        • 2021-10-28
        • 2017-11-20
        • 1970-01-01
        • 1970-01-01
        • 2015-05-27
        • 2014-09-29
        • 2016-04-09
        相关资源
        最近更新 更多