基本上,只要鼠标按下该按钮,我就会尝试再次执行按钮多次。
我需要这个带滑块的按钮。现在,我单击一个按钮,例如“增加滑块”,滑块增加1步,但现在我希望能够增加滑块很多步骤,如果我长按该按钮。
我怎么做?
你的do
循环在1000毫秒内运行多次,而mouseleave
和mouseup
处理程序永远不会有机会运行,因为their events are sitting in the message queue等待mousedown
处理程序完成贯穿该循环。
该循环设置了几千个超时,至少在200毫秒后运行。鉴于您发布的代码,这些超时实际上并没有做任何事情,因为window
's click
handler is being called, not your button's。
mouseleave
和mouseup
处理程序基本上什么都不做,因为start
将在被检查之前重置为有效时间。
我们需要两个延迟:初始点击和滑块第一次增加之间的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必要。
现在代码是单击该按钮将启动整个长按过程,无法停止它。停止进程意味着停止超时和间隔,我们可以使用window.clearTimeout()
或window.clearInterval()
(它们是相同的功能;不要告诉任何人)。我们需要保持ID setTimeout()
和setInterval()
给我们,并在mouseup
和mouseleave
处理程序中清除它们:
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);
现在按钮正在执行我们想要它做的事情,但有一个例外:短按不会做任何事情,因为我们没有使用click
处理程序,并且在调用increaseSlider()
之前正在清除超时。如果在mousedown
事件之后但在超时触发之前触发了取消事件,则应该注册一个短按。由于timeoutId
在mousedown
事件之前未定义,并且我们在超时触发后不需要它,我们可以在超时时为其分配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
。否则,在短按后,每次将鼠标移出按钮时都会触发增加。
代码现在可以工作,但需要两个全局变量,并且对特定按钮进行硬编码。让我们把它变成一个通用的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">−</button>
<progress value="25" max="50"></progress>
<button id="inc" data-change="1">+</button>
改变了什么?
increaseSlider()
参数和callback
替换了对callback.call($(this), e)
的调用。这样,任何函数都可以用作回调,因为我们在超时中使用了箭头函数,所以我们可以使用Function.call
和this
来访问回调中的触发元素。delay
和interval
,以供更广泛的使用。$.repeatingClick()
。由于jQuery对象可以表示集合以及单个元素,因此我们将原始代码包装在对$.each()
的调用中以单独访问每个元素。我们还以通常的样式返回jQuery对象。其余的是特定于这个应用程序:两个按钮来修改(<progress>
)'滑块'的值,使用自定义data-
属性的实际金额,所以我们可以给两个相同的代码。
我以前从未写过jQuery插件;围绕核心逻辑的大多数代码直接来自jquery-longpress,这是一个几乎与OP一样的jQuery插件。
尝试使用间隔而不是手动计算时间。看一下这个:
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>
您可以通过更改间隔时间来调整速度。