【问题标题】:Incrementing value continuously on mouse hold在鼠标按住时连续增加值
【发布时间】:2022-02-10 17:04:32
【问题描述】:

我有一个 HTML5“范围”控件,我想在其两侧添加一个加号 (+) 和减号 (-) 按钮。

小提琴工作正常,除了值在'单击并按住'时仅增加(或减少)一次。 虽然我想要的是它应该不断增加(或减少)。

Fiddle

HTML,

<input type='button' id='minus'/>
<div class='range-container'>
    <input id='range' type='range' min='0' max='100' step='1'/>
</div>
<input type='button' id='plus'/>

JavaScript,

$('#plus').click(function() {
    $('#range').val(parseInt($('#range').val()) + 1);
});

$('#minus').click(function() {
    $('#range').val(parseInt($('#range').val()) - 1);
});

HTML5 'number' 控件原生就有这种体验。

浏览了SO,在任何地方都找不到这个问题。我得到的最接近的是this,它再次只需单击一次。

【问题讨论】:

  • 使用 setInterval 在鼠标按下时连续运行函数。该函数的增量。清除 mouseup 的间隔并在 mousedown 时启动它。
  • @SergiuParaschiv 谢谢,会尝试。不过,我希望有一个更“原生”/jQuery 的解决方案,因为它支持数字控制。
  • @SergiuParaschiv 其实没那么简单。有很多附加条件。主要检测clickmousedown 并在没有mouseup 事件时做正确的事情,因为鼠标已经移出按钮。其次,会找到有效的延迟和缓和,并使整个事情独立于数字范围。
  • 显然。这就是为什么我没有将其发布为答案。这是一个起点。

标签: javascript jquery html


【解决方案1】:

您可以使用requestAnimationFrame 不断检查是否仍然按下任何按钮。如果仍然按下,您可以增加或减少您的值。

  • 创建一个从零开始的“数字”变量。
  • 如果按下“添加”按钮,请将“isDown”变量设置为 1。
  • 如果按下减法按钮,请将“isDown”变量设置为 -1。
  • 如果任何按钮被释放,将'isDown'变量设置为0;
  • 启动一个requestAnimationFrame 循环,不断检查“isDown”是否不为零。如果不为零,requestAnimationFrame 将通过 isDown 值更改“数字”变量。

这是示例代码和演示:

var $result=$('#result');
var number=0;
var isDown=0;
var delay=250;
var nextTime=0;

requestAnimationFrame(watcher);

$("button").mousedown(function(e){handleMouseDown(e);});
$("button").mouseup(function(e){handleMouseUp(e);});
$("button").mouseout(function(e){handleMouseUp(e);});


function handleMouseDown(e){
  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();

  // Put your mousedown stuff here
  isDown=(e.target.id=='Add')?1:-1;
}

function handleMouseUp(e){
  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();

  // Put your mouseup stuff here
  isDown=0;
}

function watcher(time){
  requestAnimationFrame(watcher);
  if(time<nextTime){return;}
  nextTime=time+delay;
  if(isDown!==0){
    number+=isDown;
    $result.text(number);
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button id=Add>Add</button>
<button id=Subtract>Subtract</button>
<span id='result'>0</span>

【讨论】:

  • 当我单击鼠标按钮并在释放鼠标之前将鼠标移出时,您的示例代码会不断计数。
  • 我也一直在努力解决这个问题。没有我可以听的活动吗?我的意思是,浏览器肯定知道按钮已被释放并相应地对其进行动画处理。使用 mouseout 是一种肮脏的黑客行为,与 UI 的工作方式不符。
  • requestAnimationFrame() 的使用很好,我一直在尝试使用 setInterval()
  • @anoopelias 检查是否所有目标浏览器都支持:caniuse.com/#feat=requestanimationframe
  • @Tomalak,它在现代浏览器中得到了很好的支持。如果您使用的是旧版浏览器,请检查此链接,其中包含一个 polyfill,如果 requestAnimationFrame 不可用,则返回使用 setInterval:creativejs.com/resources/requestanimationframe
【解决方案2】:

编辑、更新

试试

var range = $("#range")
, fx = function(elem, prop) {
  return elem
    .animate({
      value: range.prop(prop)
    }, {
      duration: 3000,
      easing: "linear",
      step: function(now) {
             elem.val(now + prop === ("max","+"||"min","-") + elem.prop("step"))
      }
    })
};

$('#plus').mousedown(function(e) {
  fx(range, "max")
});

$('#minus').mousedown(function minus(e) {
  fx(range, "min")
});

$(document).mouseup(function(e) {
  range.stop(true, false)
});

jsfiddle http://jsfiddle.net/bnesu3h9/3/

var range = $("#range")
, fx = function(elem, prop) {
  return elem
    .animate({
      value: range.prop(prop)
    }, {
      duration: 3000,
      easing: "linear",
      step: function(now) {
        elem.val(now + prop === ("max","+"||"min","-") + elem.prop("step"))
      }
    })
};

$('#plus').mousedown(function(e) {
  fx(range, "max")
});

$('#minus').mousedown(function minus(e) {
  fx(range, "min")
});

$(document).mouseup(function(e) {
  range.stop(true, false)
});
#plus {
  width: 15px;
  height: 15px;
  background-color: red;
  float: left;
}
#minus {
  width: 15px;
  height: 15px;
  background-color: blue;
  float: left;
}
.range-container {
  float: left;
  overflow: auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input type='button' id='minus' />
<div class='range-container'>
  <input id='range' type='range' min='0' max='100' step='1' />
</div>
<input type='button' id='plus' />

【讨论】:

  • 这不是很好。在释放之前尝试将鼠标指针移出按钮。也不要使用全局变量。
  • 其实挺好的。我认为这比我的解决方案要好得多。以后我会尽量记住使用animate 来处理这类事情。现在只需尊重step 属性并使其与ID 无关,一切就绪。 ;)
  • 很好 :) 是的,我知道它存在,我只需要记住去想它。
  • 我已经更新了你的小提琴。 jsfiddle.net/bnesu3h9/4。我将删除我的答案以支持这种方法。
  • 有趣的解决方案,但它不适用于我的特定情况,因为我需要的不仅仅是一步中的 CSS 更改。 (为简单起见,问题中省略了该细节。请参阅scottcheng.github.io/cropit 下的$imageCropper.cropit('zoom', .75);)。
【解决方案3】:

This answer 应该会有所帮助。

点击事件包括mouseupmousedown。您首先要单独处理mousedown,并不断检查鼠标是否仍然向下。您可以停止查看文档mouseup

【讨论】:

  • 这和轮询有什么关系?轮询与对服务器的 ajax 和 http 调用有关。
  • 是的,我知道。你链接到一篇关于http polling的文章。我认为这会造成更多的混乱,对初学者没有帮助。
  • 应该确保在指责别人之前阅读整个故事。你读过我说“是的,我知道”和“那不是重点”的那篇吗?
【解决方案4】:

对此非常基本的方法是在按下其中一个按钮时以特定间隔开始循环,在每个滴答声中更改值。单击按钮时开始,释放时停止。以下是仅用于概念演示的简单代码:

// Store the reference
var range = $('#range');

// These functions will change the value
function increment () {
    range.val(parseInt(range.val()) + 1)
}

function decrement () {
    range.val(parseInt(range.val()) - 1)
}

// Attaches polling function to element
function poll (el, interval, fn) {
    var isHeldDown = false;

    return el
    .on("mousedown", function() {
        isHeldDown = true;

        (function loop (range) {
            if (!isHeldDown) return; // Stop if it was released
            fn();
            setTimeout(loop, interval); // Run the function again       
        })();
    })
    .on("mouseup mouseleave", function () {
        isHeldDown = false; // Stop polling on leave or key release
    });
}

poll($("#plus"), 40, increment);
poll($("#minus"), 40, decrement);

JSFiddle.

在生产级版本中,您希望应用计时功能而不是恒定间隔;考虑应该开始和停止轮询的所有可能事件,这样当用户将指针移开或其他东西时它不会永远卡住;使用requestAnimationFrame更精确地控制定时功能。

【讨论】:

    【解决方案5】:

    这是一个经常被问到的问题。 我已经在一个重复的线程上回答了一个可以正常工作的 sn-p,它完全符合您的要求。

    https://stackoverflow.com/a/70957862/13795525

    function imposeMinMax(el) {
        if (el.value != '') {
            if (parseInt(el.value) < parseInt(el.min)) {
                el.value = el.min;
            }
            if (parseInt(el.value) > parseInt(el.max)) {
                el.value = el.max;
            }
        }
    }
    
    
    var index = 0;
    var interval;
    var timeout;
    var stopFlag=false;
    
    function clearAll(){
       clearTimeout(timeout);
       clearInterval(interval);
    }
    
    
    function modIn(el) {
       var inId = el.id;
       if (inId.charAt(0) == 'p') {
          var targetId = inId.charAt(2);      
          var maxValue = Number(document.getElementById(targetId).max);
          var actValue = Number(document.getElementById(targetId).value);
          index = actValue;
          if(actValue < maxValue){
             stopFlag=false;
             document.getElementById(targetId).value++;
          }else{
          stopFlag=true;
          }
          timeout = setTimeout(function(){
          interval = setInterval(function(){        
             if(index+1 >= maxValue){
                index=0;
                stopFlag=true;
             }  
             if(stopFlag==false){
                document.getElementById(targetId).value++;
             } 
             index++;
          }, 100);
          }, 500);      
       imposeMinMax(document.getElementById(targetId));
       }
       if (inId.charAt(0) == 'm') {
          var targetId = inId.charAt(2);
          var minValue = Number(document.getElementById(targetId).min);
          var actValue = Number(document.getElementById(targetId).value);
          index = actValue;
          if(actValue > minValue){
             stopFlag=false;
             document.getElementById(targetId).value--;
          }else{
             stopFlag=true;
          }
          timeout = setTimeout(function(){
             interval = setInterval(function(){        
                if(index-1 <= minValue){
                   index=0;
                   stopFlag=true;
                }  
                if(stopFlag==false){
                   document.getElementById(targetId).value--;
                } 
                index--;
             }, 100);
             }, 500);      
          imposeMinMax(document.getElementById(targetId));
       }
    }
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <title>Button example</title>
      <meta charset="utf-8">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
    </head>
    <body>
    
      <button type='button' class='btn btn-danger btn-sm ' id='mbA' onmousedown='modIn(this)' onmouseup='clearAll()' onmouseleave='clearAll()'>-</button>
      <input type='number' id='A'  onchange='imposeMinMax(this)' value='200' max='350' min='150' step='1' style='width: 50px;'>                 
      <button type='button' class='btn btn-danger btn-sm ' id='pbA' onmousedown='modIn(this)' onmouseup='clearAll()' onmouseleave='clearAll()'>+</button>&nbsp;
    
      <button type='button' class='btn btn-danger btn-sm signBut' id='mbB' onmousedown='modIn(this)' onmouseup='clearAll()' onmouseleave='clearAll()'>-</button>
      <input type='number'  id='B'  onchange='imposeMinMax(this)' value='250' max='450' min='150' step='1' style='width: 50px;'>                 
      <button type='button' class='btn btn-danger btn-sm ' id='pbB' onmousedown='modIn(this)' onmouseup='clearAll()' onmouseleave='clearAll()'>+</button>&ensp;
    
      <button type='button' class='btn btn-danger btn-sm signBut' id='mbC' onmousedown='modIn(this)' onmouseup='clearAll()' onmouseleave='clearAll()'>-</button>
      <input type='number'  id='C'  onchange='imposeMinMax(this)' value='3' max='10' min='1' step='1' style='width: 50px;'>                 
      <button type='button' class='btn btn-danger btn-sm ' id='pbC' onmousedown='modIn(this)' onmouseup='clearAll()' onmouseleave='clearAll()'>+</button>
    
    </body>
    
    
    
    </html>

    【讨论】:

    • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
    • 我也在答案中添加了 sn-p。
    猜你喜欢
    • 1970-01-01
    • 2011-12-17
    • 2020-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多