Javascript clearTimeout不处理mouseup事件
为什么在此设置中未清除超时?我如何弥补()使延迟的操作停止运行Javascript clearTimeout不处理mouseup事件,javascript,settimeout,mousemove,mouseup,cleartimeout,Javascript,Settimeout,Mousemove,Mouseup,Cleartimeout,为什么在此设置中未清除超时?我如何弥补()使延迟的操作停止运行 var active = false; var delay; window.addEventListener("mousedown", down, false); window.addEventListener("mouseup", up, false); window.addEventListener("mousemove", move, false); function down(e) { active = true
var active = false;
var delay;
window.addEventListener("mousedown", down, false);
window.addEventListener("mouseup", up, false);
window.addEventListener("mousemove", move, false);
function down(e) {
active = true;
console.log("down")
window.scrollTo(0,document.body.scrollHeight);
}
function up(e) {
active = false;
clearTimeout(delay); //expecting this to clear delay
console.log("up")
window.scrollTo(0,document.body.scrollHeight);
}
function move(e) {
if (active) {
delay = setTimeout(function() {
console.log("move")
window.scrollTo(0,document.body.scrollHeight);
}, 50);
}
}
希望在mouseup上清除延迟,但它仍会执行。每次移动都会超时。它不会取代最后一个 你的代码基本上是这样的
delay = setTimeout(function() { } <-- will run
delay = setTimeout(function() { } <-- will run
delay = setTimeout(function() { } <-- will run
delay = setTimeout(function() { } <-- will run
delay = setTimeout(function() { } <-- will run
delay = setTimeout(function() { } <-- will run
delay = setTimeout(function() { } <-- cancels this one
window.clearTimeout(delay)
如果您需要不止一次地移动到fire,那么您需要查看节流脚本 答复:
在您的代码中有一些东西需要调整:
- 不要用新的
计时器连续重新分配超时
,只需使用延迟
间隔
- 只有当状态为活动且延迟不存在时,才应设置计时器。这将停止现有的多个计时器
- 设置计时器时,包含计时器的变量设置为返回整数。这是当前作用域中计时器的ID李>
- 清除计时器时,变量不会重置为未定义的——它保持相同的整数/ID。这是因为您没有清除变量,作用域会停止与变量所在的ID匹配的计时器李>
- 由于上述原因,在清除该变量以进行存在性检查后,必须将其显式设置为
(或某些其他undefined
值)李>falsy
var-active=false;
无功延迟;
window.addEventListener(“mousedown”,down,false);
window.addEventListener(“mouseup”,up,false);
addEventListener(“mousemove”,move,false);
功能下降(e){
主动=真;
控制台日志(“关闭”)
scrollTo(0,document.body.scrollHeight);
}
功能启动(e){
主动=假;
clearTimeout(delay);//预期这将清除延迟
延迟=未定义;
控制台日志(“向上”)
scrollTo(0,document.body.scrollHeight);
}
功能移动(e){
如果(活动){
如果(!延迟){
延迟=设置间隔(函数(){
控制台日志(“移动”)
scrollTo(0,document.body.scrollHeight);
}, 50);
}
}
else{//浏览器队列问题时的回退
如果(延迟){
清除超时(延迟);
延迟=未定义;
}
}
}
因此,我从回复中了解到,每次执行move()
时,setTimeout
都会生成一个新的独立计时器。我的理解是,每一个新的计时器都会覆盖上一个计时器,但由于情况并非如此,我不得不考虑其他事情
我并没有真正解释我需要通过延迟实现什么,所以让我澄清一下。我想为一个动作创建一个超时,如果该动作已经x个时间段没有执行。在操作上使用setTimeout,它自己造成了一个问题,即即使在mouseup事件之后,该操作仍可能有多个排队执行等待发生
因此,我在一个新变量上使用了setTimeout,该变量充当操作的锁。结果是以下代码:
var active = false;
var actionTimeout = false;
var actionTimeStamp;
var actionLock = false;
window.addEventListener("mousedown", down, false);
window.addEventListener("mouseup", up, false);
window.addEventListener("mousemove", move, false);
function down(e) {
active = true;
console.log("down")
window.scrollTo(0,document.body.scrollHeight);
}
function up(e) {
active = false;
console.log("up")
window.scrollTo(0,document.body.scrollHeight);
}
function move(e) {
if (active) {
if ((Date.now() - actionTimeStamp > 500) && (!actionTimeout)) { // get time elapsed and compare to threshold (500ms)
actionTimeout = true; //this is for the if statement above to prevent multiple timeouts
actionLock = false; // set the lock
setTimeout(function() { // remove lock after 50ms
actionTimeout = false;
actionLock = true;
actionTimeStamp = Date.now(); // timestamp here to make sure we don't lock again to soon. (helps if setTimeout is => than threshold.
}, 50);
}
if (actionLock) { //do our action
console.log("move")
window.scrollTo(0,document.body.scrollHeight);
actionTimeStamp = Date.now(); // timestamp last execution
}
}
}
感谢大家的点评和回答。非常感谢。您只有50毫秒的延迟。您有一个计时器变量:
delay
,但在mousemove上会触发一大堆MouseEvents,每个都会覆盖delay的值,因此最多只能清除将设置的许多超时中的一个。@Pointy是正确的<代码>设置超时使用毫秒,而不是秒。如果这是你想要的,在50毫秒以下点击有点困难…每次移动都会让你产生另一个计时器。计时器处于活动状态,您可以创建一个新的、另一个和另一个。。。。。你只能取消最后一个…节流或去Bouncinghi!不幸的是,我认为这不会奏效。清除计时器时,变量不会更改,并且始终为正整数。因此,在“移动”时,延迟永远不会是真的。这意味着只有当你在一个地方拖拽并停留足够长的时间,计时器的功能才会启动,以至于计时器不会被清除。在这里查看可能更容易:@zfrisch不管delay
保持什么,他们都在检查活动状态。if(delay)
只是为了避免在分配clearTimeout之前调用它,这是完全无用的,因为clearTimeout(未定义)是一个noop,但拥有它本身并不是问题。@kaido它确实很重要。您尝试过演示吗?@zfrisch此答案中的代码将在分配新超时之前取消任何仍处于活动状态的超时<代码>延迟
应保持真实,以使此代码正常工作。而你的代码笔恰恰暴露了这个答案所说的应该暴露的行为:“move”只有在mousemove事件发生后才被记录,当你一直按下按钮而不移动50毫秒时。我已经测试了这个代码,它是有效的。然而,即使我松开鼠标按钮并完全停止移动鼠标,大约十分之一的“移动”消息仍会被无限打印。@bewww在这里尝试了几十次后,我无法重现该问题:。我不是说你错了,但首先你确定你把整个片段都复制了一遍吗?特别是延迟
设置为未定义
的部分非常重要。第二,如果你有,你能告诉我你是如何拖动/点击以获得无限“移动”的,这样我就可以尝试复制它吗?谢谢我只是一次又一次的点击、拖动和释放。这里的代码片段似乎不太可能被卡住,更像是五十分之一。这更可能发生在JSFIDLE上。此外,在单击鼠标时尝试做圆周运动,这似乎会增加可能性。@bewww我添加了一个后备方案。我真的无法复制它,所以请让我知道它是如何进行的-但我认为你所经历的可能是一个与B有多大不同的问题
var active = false;
var actionTimeout = false;
var actionTimeStamp;
var actionLock = false;
window.addEventListener("mousedown", down, false);
window.addEventListener("mouseup", up, false);
window.addEventListener("mousemove", move, false);
function down(e) {
active = true;
console.log("down")
window.scrollTo(0,document.body.scrollHeight);
}
function up(e) {
active = false;
console.log("up")
window.scrollTo(0,document.body.scrollHeight);
}
function move(e) {
if (active) {
if ((Date.now() - actionTimeStamp > 500) && (!actionTimeout)) { // get time elapsed and compare to threshold (500ms)
actionTimeout = true; //this is for the if statement above to prevent multiple timeouts
actionLock = false; // set the lock
setTimeout(function() { // remove lock after 50ms
actionTimeout = false;
actionLock = true;
actionTimeStamp = Date.now(); // timestamp here to make sure we don't lock again to soon. (helps if setTimeout is => than threshold.
}, 50);
}
if (actionLock) { //do our action
console.log("move")
window.scrollTo(0,document.body.scrollHeight);
actionTimeStamp = Date.now(); // timestamp last execution
}
}
}