使用setTimeout()代替setInerval()易错点
跟着b站尚硅谷的JS基础视频自己在做 定时器案例 时出现了一些小错误。
案例描述
- 正确
- 错误
实现过程
不想看的可跳过此部分
//Code01
//一些获取元素对象初始化
let box1 = document.getElementById("box1"); //粉色盒子
let box1Width = parseInt(getStyle(box1, "width")); //获取粉色盒子的width,这么写是为了提高浏览器的兼容性
let btn = document.getElementById("btn"); //键盘按钮
let line = document.getElementById("line"); //黑线
let id, flag = false; //id为定时器的唯一标识符 flag用来在定时函数中判断按钮是否按下
//btn按钮的响应事件
btn.onclick = function () {
flag = true;
};
/*
* 定义一个函数,用来获取指定元素的当前的样式
* 参数:
* obj 要获取样式的元素
* name 要获取的样式名
*/
//正常浏览器的方式,具有getComputedStyle()方法
//IE8及其以下,使用 对象.currentStyle.样式名 的方法
function getStyle(obj, name) {
return window.getComputedStyle ? getComputedStyle(obj, null)[name] : obj.currentStyle[name];
}
setInterval()实现
Code02
//使用setInterval()实现
id = setInterval(function () {
if (flag) {
box1.style.left = box1.offsetLeft + 5 + "px";
}
//box1碰到line就停止
if ((box1.offsetLeft + box1Width) == line.offsetLeft) {
clearTimeout(id);
}
}, 50);
setTimeout()实现
//使用setTimeout()来实现
function moveRight() {
//box1碰到line就停止
if (flag) {
box1.style.left = box1.offsetLeft + 5 + "px";
}
id= setTimeout(moveRight, 50);
// console.log(id);
// id = setTimeout("moveRight()", 50);
//报错:VM42:1 Uncaught ReferenceError: moveRight is not defined 看网上说是要在全局作用域下才能这么写
if ((box1.offsetLeft + box1Width) == line.offsetLeft) {
// console.log("id " + id);
clearTimeout(id);
}
};
moveRight();
遇到的错误
setTimeout()中回调函数中应引用问题
//Code03
//使用setTimeout()来实现
function moveRight() {
if (flag) {
box1.style.left = box1.offsetLeft + 5 + "px";
}
//box1碰到line就停止
// // 判断box1右边是否碰到了线
if ((box1.offsetLeft + box1Width) == line.offsetLeft) {
clearTimeout(id);
}
id = setTimeout("moveRight()", 50);
//【报错1】:VM42:1 Uncaught ReferenceError: moveRight is not defined
};
moveRight();
报错:VM42:1 Uncaught ReferenceError: moveRight is not defined
解决方法
//Code04
id = setTimeout(moveRight, 50);
原因
因为我是在window.onload属性下实现的该功能,我看一个博主说得要在该函数得要在全局作用域下才能写成"moveRight()"。
原因感觉不是特别清除,但是能够解决【求解答】
回调函数内id = setTimeout()和clearTimeout(id)使用顺序问题
哈哈哈哈,其实我Code03代码中存在错误,不知道有没有人发现,那就是我标题中所说的问题
正确操作
//Code05
//使用setTimeout()来实现
function moveRight() {
if (flag) {
box1.style.left = box1.offsetLeft + 5 + "px";
}
//setTimeout()在前面
id = setTimeout(moveRight(), 50);
//clearTimeout()在后面
if ((box1.offsetLeft + box1Width) == line.offsetLeft) {
clearTimeout(id);
}
};
moveRight();
原因:
如果将clearTimeout(id)写在前面
如果将clearTimeout(id)写在后面
进一步解释
- 错误顺序
//使用setTimeout()来实现
function moveRight() {
//box1碰到line就停止
if (flag) {
box1.style.left = box1.offsetLeft + 5 + "px";
}
if ((box1.offsetLeft + box1Width) == line.offsetLeft) {
//在控制台中输出
console.log("id " + id);
clearTimeout(id);
}
id = setTimeout(moveRight, 50);
//在控制台中输出
console.log(id);
};
moveRight();
我们可以看到clearTimeout()清除的是上一个延时定时器id = 14,而没有把新生成的演示定时器id = 15清除。
- 正确顺序
//使用setTimeout()来实现
function moveRight() {
//box1碰到line就停止
if (flag) {
box1.style.left = box1.offsetLeft + 5 + "px";
}
id = setTimeout(moveRight, 50);
//在控制台中输出
console.log(id);
if ((box1.offsetLeft + box1Width) == line.offsetLeft) {
//在控制台中输出
console.log("id " + id);
clearTimeout(id);
}
};
moveRight();
我们可以看到clearTimeout()清除的是新添加的定时构造函数。
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>定时器01</title>
<style>
#box1 {
position: absolute;
top: 100px;
left: 50px;
width: 100px;
height: 100px;
background-color: pink;
}
#line {
position: absolute;
top: 0;
left: 300px;
width: 0;
height: 1000px;
border-left: 1px solid #000;
}
</style>
<script>
window.onload = function () {
//一些获取元素对象初始化
let box1 = document.getElementById("box1"); //粉色盒子
let box1Width = parseInt(getStyle(box1, "width")); //获取粉色盒子的width,这么写是为了提高浏览器的兼容性
let btn = document.getElementById("btn"); //键盘按钮
let line = document.getElementById("line"); //黑线
let id, flag = false; //id为定时器的唯一标识符 flag用来在定时函数中判断按钮是否按下
btn.onclick = function () {
flag = true;
};
// //使用setInterval()实现
// id = setInterval(function () {
// if (flag) {
// box1.style.left = box1.offsetLeft + 5 + "px";
// }
// //box1碰到line就停止
// if ((box1.offsetLeft + box1Width) == line.offsetLeft) {
// clearTimeout(id);
// }
// }, 50);
//使用setTimeout()来实现
function moveRight() {
//box1碰到line就停止
if (flag) {
box1.style.left = box1.offsetLeft + 5 + "px";
}
id = setTimeout(moveRight, 50);
// console.log(id);
// id = setTimeout("moveRight()", 50);
//报错:VM42:1 Uncaught ReferenceError: moveRight is not defined 看网上说是要在全局作用域下才能这么写
if ((box1.offsetLeft + box1Width) == line.offsetLeft) {
// console.log("id " + id);
clearTimeout(id);
}
};
moveRight();
};
/*
* 定义一个函数,用来获取指定元素的当前的样式
* 参数:
* obj 要获取样式的元素
* name 要获取的样式名
*/
//正常浏览器的方式,具有getComputedStyle()方法
//IE8及其以下,使用 对象.currentStyle.样式名 的方法
function getStyle(obj, name) {
return window.getComputedStyle ? getComputedStyle(obj, null)[name] : obj.currentStyle[name];
}
</script>
</head>
<body>
<button id="btn">点击按钮以后box1向右移动</button>
<div id="box1"></div>
<div id="line"></div>
</body>
</html>