I cant use setTimeout and event.clientX in the same function without getting this error: "Uncaught RangeError: Maximum call stack size exceeded"

I cant use setTimeout and event.clientX in the same function without getting this error: "Uncaught RangeError: Maximum call stack size exceeded"

我想每隔一秒设置一个与光标位置相等的元素位置。但是一旦我在函数中包含 setTimout 属性,它就会停止工作并在日志中打印以下错误:"Uncaught RangeError: Maximum call stack size exceeded"。
我曾尝试 运行 没有超时的代码,但随后页面冻结。

这是我无法开始工作的代码:


function moveElement() {
    while (true) {
        x = event.clientX;
        y = event.clientY;
        document.getElementById("status").innerHTML = x + " " + y; //This line is not important
        setTimeout(moveElement(), 1000);
        document.getElementById("test").style.color = "blue";
        document.getElementById("test").style.left = x + "px";
        document.getElementById("test").style.top = y + "px";
    }
};
当我尝试在函数外 运行 event.clientX 时也会出现此错误:"Uncaught TypeError: Cannot read property 'clientX' of undefined"
有人可以看看我的代码有什么问题,或者只是告诉我另一种方法让它工作(请不要 jQuery)?谢谢你。

/HamMan4Ever

你有这条线:

setTimeout(moveElement(), 1000);

应该是:

setTimeout(moveElement, 1000);

函数末尾的括号会立即调用它。所以这个函数只是一遍又一遍地调用自己。您想传递对超时应在指定时间后调用的函数的引用。

Uncaught RangeError: Maximum call stack size exceeded

您还应该删除 while(true) ,它将永远循环。这很可能是您收到上述错误的原因。如果您想每秒调用此函数,只需使用 setTimeout,它将等待指定的时间量,然后调用您传递给它的函数引用。

Uncaught TypeError: Cannot read property 'clientX' of undefined

发生这种情况是因为不存在事件变量。通常一个事件被传递给一个函数,该函数已作为某个事件的处理程序附加。

这是一个附加事件并以某种方式使用 clientX/clientY 的示例。也许它会帮助您理解和扩展它以完成您想做的任何事情:

Fiddle: http://jsfiddle.net/tqpvkjd9/

HTML:

<div id="test">some text</div>

JS:

function moveElement (event) {
    var x = event.clientX;
    var y = event.clientY;
    var test = document.getElementById("test");
    test.style.color = "blue";
    test.style.left = x + "px";
    test.style.top = y + "px";
};

document.addEventListener('mousemove', moveElement);

CSS:

div {
    height: 100px;
    width: 100px;
    background: red;
    position: absolute;
    top: 0;
    left: 0;
}

最后,您真的应该像我上面那样使用 var 声明 x 和 y。如果没有 var,它们将被假定为全局变量,这通常并不好。

setTimeout 的第一个参数必须是一个函数。当您使用像 moveElement() 这样的代码时,您是在 调用 函数(再次),而不是仅仅提供对它的引用。所以我认为你最好做这样的事情: setTimeout(moveElement, 1000);

while (true) 循环导致您的页面冻结,因为它是一个永恒的循环;它会 运行 你的代码永远重复,不会给你的浏览器喘息的时间。可怜的东西。

此示例等到鼠标停止移动,然后等待一秒钟,然后应用新位置。 我可以创建另一个示例,每秒更新一次位置,尽管等待鼠标停止移动可能是个好主意。

此代码等待鼠标移动,然后清除任何现有的 运行 计时器,然后设置一个新计时器。它还捕获并存储有关鼠标移动的信息以备后用。 由于 mousemove 事件是一个重复事件(每当您移动鼠标时它都会触发一千次)这就是为什么每当鼠标移动时,所有计时器都会被清除以避免同时设置多个计时器。

这段代码的最终结果是,当你移动鼠标时,它会等到你停止移动鼠标,等待一秒钟,然后设置 div 坐标。

如果有什么我可以为您做的,请在评论中告诉我。

window.addEventListener('load',function(){//when the page loads
  //initialize all variables.
  var timer = false;
  var updateTracking = false;
  var x = 0;
  var y = 0;
  window.addEventListener('mousemove',function(e){//when the mouse is moved.
    clearTimer();//clear the existing timer
    updateTracking = true;//set the flag so that the if statement knows the mouse has been moved.
    x = e.x;//get the X coord of the mouse move
    y = e.y;//get the Y coord of the mouse move
    setTimer();//set a timer for 1 second.
  });
  //the function that sets the timer.
  function setTimer(){
      //set the "timer" variable to a timer function
      timer = window.setTimeout(function(){
        if(updateTracking == true){//if the mouse has been moved
          var elem = document.getElementById('theDiv');//get the element
          updateTracking = false;//reset the flag since the element has been updated
          elem.style.top = y+'px';//set the Y coord of the element
          elem.style.left = x+'px';//set the X coord of the element
        }
      },1000);
  }
  function clearTimer(){//cleat timer function; clears any existing timers
    window.clearTimeout(timer);//clear the timer  
  }
});
#theDiv{
  width:30px;
  height:30px;
  background:red;
  position:absolute;
}
<div id="theDiv"></div>

这是另一个代码片段,向您展示了 mousemove 事件的工作原理。只需打开您的控制台并移动鼠标...

window.onload = function(){
  window.onmousemove = function(){
    console.log('the mouse was moved');
  };
};