鼠标移动后无限循环

endless while loop after mousemove

我快要疯了。 我想在鼠标移动时显示一个元素,并在最后一次移动鼠标后 10 秒隐藏它。

我写了这个:

document.addEventListener("DOMContentLoaded", function(event) {
  var time = 0;
  document.addEventListener("mousemove", function(event) {
    console.log('$');
    document.getElementsByClassName("mybar")[0].style.visibility = 'visible';
    time = 0;
    while (time < 11) {
      setTimeout(function() {
        time++
      }, 1000);
      console.log(time, time == 10);
      if (time == 10) {
        document.getElementsByClassName("mybar")[0].style.visibility = 'hidden';
      }
    }
  });
});
<div class='mybar'>
  <h1> TESTING </h1>
</div>

为什么会死循环? 为什么它不按条件退出?为什么 if 永远不会获取 'true' 参数? 注意:不要运行这样...它会杀死你的标签。

首先,您无需等待 DOMContentLoaded 将事件侦听器添加到 document,因为如果您这样做了,您将无法在第一时间添加 DOMContentLoaded地点。

无限循环是因为setTimeout没有暂停脚本。它会在您提供的时间安排回调,无论那个时间如何,回调 都不会 运行 直到线程中的当前 运行ning 代码完成,这永远不会发生,因为你没有增加 time 变量。

所以循环永远不会结束,所以线程永远不会可用,所以你的回调永远不会 运行,所以 time 永远不会递增。

最后,在一个事件处理程序中启动一个 setTimeout,它共享一个局部变量并且在像 mousemove 这样的事件上非常快速地执行,很容易产生意想不到的结果。例如,在您的代码中,每次处理程序 运行 时,它都会将 time 重置为 0,这似乎不是您想要的。


一个解决方案是放弃循环,安排 10 秒的可见性,并通过使用布尔变量防止处理程序中代码的主要部分在此期间 运行ning。

var timer = null;
document.addEventListener("mousemove", function(event) {
    var myBar = document.querySelector(".mybar");
    if (!myBar) {
      return; // there's no mybar element
    }


    if (timer == null) {
      myBar.style.visibility = 'visible';
    } else {
      clearTimeout(timer); // clear the currently running timer
    }

    // set to hidden in 10 seconds
    timer = setTimeout(function() {
      myBar.style.visibility = 'hidden';
      timer = null; // clear the timer
    }, 10000);
});

我也切换到 querySelector 而不是 getElementsByClassName 因为它更短更干净。在设置样式之前,我使用了一个变量来确保找到元素。

您需要一个超出 mousemove 范围的标志,告诉您的听众您已经 运行。

if(running) return; 
running = true;

在上下文中:

document.addEventListener("DOMContentLoaded", function(event) {
  var time = 0;
  var running = false;
  document.addEventListener("mousemove", function(event) {

    console.log('$');

    if(running) return;
    running = true;

    document.getElementsByClassName("mybar")[0].style.visibility = 'visible';
    time = 0;
    while (time < 11) {
      setTimeout(function() {
        time++
      }, 1000);
      console.log(time, time == 10);
      if (time == 10) {
        document.getElementsByClassName("mybar")[0].style.visibility = 'hidden';
      }
    }
  });
});

这是一种使用常规 JavaScript 的方法。如果你的浏览器不兼容 ES6,你可以用正则函数表达式替换箭头函数。该示例在 2 秒而不是 10 秒后隐藏文本,这样您就可以看到它的工作,而不必浪费额外的 8 秒。

//hide by default
document.getElementById('myBar').style.display = 'none';

var timer = null;

var hideDivTimer = () => {
  timer = setTimeout(() => {
    document.getElementById('myBar').style.display = 'none';
  }, 2000);
};

document.addEventListener('mousemove', () => {
  clearTimeout(timer);
  document.getElementById('myBar').style.display = 'inline';
  hideDivTimer();
});
<body>
  <div id='myBar'>
    <h1> TESTING </h1>
  </div>
</body>