我无法在同一函数中使用Settimeout和event.clientx而不会获得此错误:“未接来的RangeRor:最大呼叫堆栈大小超过了”
我想每秒将元素位置设置为等于光标位置。但是,只要我在函数中包含 setTimout 属性,它就会停止工作并在日志中打印以下错误:“Uncaught RangeError:超出最大调用堆栈大小”。
我尝试运行代码而不设置超时,但页面冻结。
这是我无法运行的代码:
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";
}
};
此示例等待鼠标停止移动,然后等待一秒钟,然后应用新位置。 我可以创建另一个示例,每秒更新一次位置,尽管等待鼠标停止移动可能是一个好主意。
此代码等待鼠标移动,然后清除正在运行的任何现有计时器,然后设置一个新的计时器。它还捕获并存储有关鼠标移动的信息以供以后使用。 由于 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');
};
};
setTimeout
的第一个参数必须是一个函数。当您使用
moveElement()
之类的代码时,您是
再次调用
该函数,而不是仅提供对它的引用。所以我认为您最好这样做:
setTimeout(moveElement, 1000);
while (true)
循环导致您的页面冻结,因为它是一个永恒循环;它将重复运行您的代码,永远不间断,并且不会给您的浏览器喘息的时间。可怜的东西。
您有此行:
setTimeout(moveElement(), 1000);
应为:
setTimeout(moveElement, 1000);
函数末尾的括号会立即调用它。因此,此函数只是一遍又一遍地调用自身。您想将引用传递给 timeout 应在指定时间后调用的函数。
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,它们将被视为全局变量,这通常不太好。