【问题标题】:How does clearTimeout work, for clearing timeouts when the previous one is still running?clearTimeout 如何在前一个仍在运行时清除超时?
【发布时间】:2019-01-28 15:15:44
【问题描述】:

我正在为我的视频创建一个播放和暂停按钮。超时完成后,该视频将消失,因为它将关闭 .active 类,这会将其恢复为 0 不透明度。我已将此绑定到onmousemove为此,我正在使用 clearTimeout。

我无法让它工作。播放按钮会闪烁,因为类不断添加。

这是我的功能

const togglePlay = (...args) => playButton.classList.toggle(...args);
var timer = null;
     vid.onmousemove = function(){

        if (timer!= null){
            clearTimeout(timer);
        }
        else {
            togglePlay("active");
            timer = setTimeout(() => {
                togglePlay("active");
                stopTime();
            }, 2000);
        }
     }

我已经阅读了多个其他有同样问题的帖子。我尝试实现这个:How to use clearTimeout

我从另一个帖子中得到了 timer=null。

我还尝试了另一种方法,即禁用 togglePlay。这确实达到了我想要的效果,但是通过测试控制台日志,它仍然在后台触发了很多。

我就是这样做的

     var timer = null;
     vid.onmousemove = function(){


        if (timer != null){
            console.log("TimedOut"); 
        }
        else {
            //right here is the mistake, this is not a timer
            timer = togglePlay("active");
            setTimeout(() => {
                togglePlay("active");
                timer = null;
                console.log("setTimeout");
            }, 2000);  
        }
     }

这种代码虽然违背了 clearTimeout 的目的。所以我的问题真的。我在 setTimeout 上做错了什么?

【问题讨论】:

  • 为什么要使用 onmousemove 来清除超时?我很困惑为什么你在这里实际上需要超时。是2秒后暂停播放吗?或者在鼠标移动时暂停播放?抱歉,我对您到底想要实现什么感到有点困惑
  • 这就像您在观看 YouTube 视频,甚至是 Netflix。当您将鼠标移到窗口上时,将出现暂停按钮。但是当您停止移动鼠标时,它会在设定的时间后淡出。这就是我想要达到的目标。它只会在 2 秒内切换一个类。
  • mousemove 只要鼠标在移动就会持续触发;你可能想要mouseenter。 (或者,如果您需要捕捉元素内的运动,debounce 事件。)
  • 我知道它确实在移动,但我想知道的是如何完全阻止它发射。我确实阅读了 debounce,但我发现很难理解它,所以我尝试先自己构建它。

标签: javascript


【解决方案1】:

如果您在调用 setTimeout 之前删除了对 togglePlay 的调用,那么您首先显示的函数应该可以正常工作:

const vid = document.querySelector('#foo');

const togglePlay = (...args) => vid.classList.toggle(...args);

var timer = null;
vid.onmousemove = function(){
  if (timer){ clearTimeout(timer); }
  timer = setTimeout(() => {
      togglePlay("active");
      // stopTime();
  }, 500);

}
#foo {
  width: 300px;
  height: 200px;
  background: #c00;
}

#foo.active {
  background: #090;
}
<div id="foo"></div>

这段代码去抖动每次鼠标移动的动作。如果您想要节流,请这样做:

const vid = document.querySelector('#foo');

const togglePlay = (...args) => vid.classList.toggle(...args);

var timer = null;
vid.onmousemove = function(){
  if (!timer){
    timer = setTimeout(() => {
      togglePlay("active");
      timer = null;
      // stopTime();
    }, 500);
  }
}
#foo {
  width: 300px;
  height: 200px;
  background: #c00;
}

#foo.active {
  background: #090;
}
<div id="foo"></div>

【讨论】:

  • 谢谢!最好接受你的回答,因为它也让我明白了超时功能!
【解决方案2】:

您似乎想使用计时器来实现一个冷却期,在此期间不允许更改类。

在这种情况下,当计时器变量为非空时什么都不做,但在延迟到期时也将变量设置回null

var timer = null;
vid.onmousemove = function(){
    if (timer !== null) return; // Don't do anything if cool-down period is not yet over
    togglePlay("active");
    timer = setTimeout(() => {
        togglePlay("active");
        timer = null; // Cool-down is over now.
        stopTime();
    }, 2000);
}

【讨论】:

  • 这行得通!所以你没有返回我的控制台日志,而是返回了?
  • 嗯,你的两个代码版本都有一些不同的地方。第一个不应该清除计时器,第二个没有为timer 分配正确的值。第一个也没有将计时器设置回null
【解决方案3】:

如果我很好地理解了您的问题,您可能需要将 timerid 存储在一个数组上,而不是一个简单的变量上。使用:

var timers = [];

timers.push(setTimeout(...));

对于明确的超时使用:

if (timers.length > 0)

然后:

for (var i = 0; i < timers.length; ++i) {
    clearTimeout(timers[i]);
}
timers = [];

但是我个人不喜欢使用清除超时选项。相反,我通常使用存储在局部变量中并作为参数传递给超时的计时器实例。然后我在计时器内部检查这是最后一个调用的还是我感兴趣的。

var localctr = 0;
setTimeout(function(thisctr) {
    if (thisctr == localctr) {
        // ... this is the latest
    }
}, 2000, ++localctr);

在这种方法上,如果您在其他事件上增加 localctr 将有效地禁用计时器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-18
    相关资源
    最近更新 更多