长按一下按钮就会产生很多即时点击,我无法阻止它!

问题描述 投票:-1回答:2

基本上,只要鼠标按下该按钮,我就会尝试再次执行按钮多次。

我需要这个带滑块的按钮。现在,我单击一个按钮,例如“增加滑块”,滑块增加1步,但现在我希望能够增加滑块很多步骤,如果我长按该按钮。

我怎么做?

javascript jquery jquery-ui
2个回答
2
投票

你的do循环在1000毫秒内运行多次,而mouseleavemouseup处理程序永远不会有机会运行,因为their events are sitting in the message queue等待mousedown处理程序完成贯穿该循环。

该循环设置了几千个超时,至少在200毫秒后运行。鉴于您发布的代码,这些超时实际上并没有做任何事情,因为window's click handler is being called, not your button's

mouseleavemouseup处理程序基本上什么都不做,因为start将在被检查之前重置为有效时间。

So how do we fix it?

我们需要两个延迟:初始点击和滑块第一次增加之间的1000毫秒延迟,以及滑块之间的200毫秒延迟增加。如果用户在前1000毫秒内取消,我们会将其视为单击。如果用户在重复开始后取消,我们不应将其视为点击。 (我们将“取消”定义为释放鼠标按钮或将光标移离按钮。这意味着在UI按钮上按下鼠标按钮并将光标移开将计为单击,但代码将更简单。)

我们可以通过设置超时来设置延迟,超时在1000毫秒后设置一个间隔,每隔200毫秒,增加滑块。由于规范的最后一行,我们不会使用click事件来增加滑块:

如果用户在重复开始后取消,我们不应将其视为点击。

因此,我们将为滑块增加代码提供自己的函数increaseSlider()(无论如何这是一个好习惯):

function startLongClick (e) {
  window.setTimeout(() => {
    increaseSlider();
    window.setInterval(() => {
      increaseSlider();
    }, 200);
  }, 1000);
}
$('#button').on('mousedown', startLongClick);

我们在超时时首次调用increaseSlider(),因此滑块在初始点击后首先增加1000毫秒,而不是1200.我们在超时和间隔中使用箭头函数,因为arrow functions don't redefine this,所以我们可以参考触发<button> if必要。

I can't stop it!

现在代码是单击该按钮将启动整个长按过程,无法停止它。停止进程意味着停止超时和间隔,我们可以使用window.clearTimeout()window.clearInterval()(它们是相同的功能;不要告诉任何人)。我们需要保持ID setTimeout()setInterval()给我们,并在mouseupmouseleave处理程序中清除它们:

let intervalId;
let timeoutId;

function startLongClick (e) {
  timeoutId = window.setTimeout(() => {
    increaseSlider();
    intervalId = window.setInterval(() => {
      increaseSlider();
    }, 200);
  }, 1000);
}

function cancelLongClick () {
  window.clearInterval(intervalId);
  window.clearTimeout(timeoutId);
}

$('#button').on('mousedown', startLongClick);
$('#button').on('mouseup', cancelLongClick);
$('#button').on('mouseleave', cancelLongClick);

What about the short click?

现在按钮正在执行我们想要它做的事情,但有一个例外:短按不会做任何事情,因为我们没有使用click处理程序,并且在调用increaseSlider()之前正在清除超时。如果在mousedown事件之后但在超时触发之前触发了取消事件,则应该注册一个短按。由于timeoutIdmousedown事件之前未定义,并且我们在超时触发后不需要它,我们可以在超时时为其分配undefined并使用它来确定是否应该注册一个短按:

let intervalId;
let timeoutId;

function startLongClick (e) {
  timeoutId = window.setTimeout(() => {
    timeoutId = undefined;
    increaseSlider();
    intervalId = window.setInterval(() => {
      increaseSlider();
    }, 200);
  }, 1000);
}

function cancelLongClick () {
  window.clearInterval(intervalId);
  if (timeoutId) {
    increaseSlider();
    window.clearTimeout(timeoutId);
    timeoutId = undefined;
  }
}

$('#button').on('mousedown', startLongClick);
$('#button').on('mouseup', cancelLongClick);
$('#button').on('mouseleave', cancelLongClick);

我们也在短击代码中将timeoutId设置为undefined。否则,在短按后,每次将鼠标移出按钮时都会触发增加。

More buttons!

代码现在可以工作,但需要两个全局变量,并且对特定按钮进行硬编码。让我们把它变成一个通用的jQuery插件*:

(($) => {
  $.fn.repeatingClick = function (callback, delay = 500, interval = 200) {
    return this.each(function () {
      let intervalId;
      let timeoutId;
      function startLongClick (e) {
        timeoutId = window.setTimeout(() => {
          timeoutId = undefined;
          callback.call($(this), e);
          intervalId = window.setInterval(() => {
            callback.call(this, e);
          }, interval);
        }, delay);
      }
      function cancelLongClick (e) {
        window.clearInterval(intervalId);
        if (timeoutId) {
          callback.call(this, e);
          window.clearTimeout(timeoutId);
          timeoutId = undefined;
        }
      }
      $(this).on('mousedown', startLongClick);
      $(this).on('mouseup', cancelLongClick);
      $(this).on('mouseleave', cancelLongClick);
    });
  }
})(jQuery);

function modifySlider (e) {
  let modifier = Number($(this).data('change'));
  $('progress').attr('value', Number($('progress').attr('value')) + modifier);
}

$('button').repeatingClick(modifySlider);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="dec" data-change="-1">&minus;</button>
<progress value="25" max="50"></progress>
<button id="inc" data-change="1">+</button>

改变了什么?

  • increaseSlider()参数和callback替换了对callback.call($(this), e)的调用。这样,任何函数都可以用作回调,因为我们在超时中使用了箭头函数,所以我们可以使用Function.callthis来访问回调中的触发元素。
  • 将超时和间隔中的延迟参数化为delayinterval,以供更广泛的使用。
  • 把所有东西都放在一个新的jQuery函数中,$.repeatingClick()。由于jQuery对象可以表示集合以及单个元素,因此我们将原始代码包装在对$.each()的调用中以单独访问每个元素。我们还以通常的样式返回jQuery对象。

其余的是特定于这个应用程序:两个按钮来修改(<progress>)'滑块'的值,使用自定义data-属性的实际金额,所以我们可以给两个相同的代码。

我以前从未写过jQuery插件;围绕核心逻辑的大多数代码直接来自jquery-longpress,这是一个几乎与OP一样的jQuery插件。


1
投票

尝试使用间隔而不是手动计算时间。看一下这个:

var value = 0
var addval;
var press = false;

$('#button').on('mousedown', function (e) {
	press = true;
	increaseValue();
	return false;
});


$('#button').on('mouseleave', function (e) {
    clearInterval(addval);
	return false;
});

$('#button').on('mouseenter', function(e) {
	if (press)
		increaseValue();
});

$('#button').on('mouseup', function (e) {
	press = false;
    clearInterval(addval);
	return false;
});

function increaseValue() {
	addval = setInterval(function(){
		value++;
		$("#counter").text(value);
	}, 100);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="button">Press me</button>
<div id="counter">0</div>

您可以通过更改间隔时间来调整速度。

© www.soinside.com 2019 - 2024. All rights reserved.