计时器方法
setInterval
每个一段时间执行一次函数
setInterval(() => {
console.log("hello")
},1000)//每间隔一秒打印hello
在网页中显示当前时间
<h1></h1>
<script>
let h1 = document.querySelector("h1");
setInterval(()=>{
let timeNow = new Date();
let hours = timeNow.getHours()<10?"0"+timeNow.getHours():timeNow.getHours();//个位数前面补0
let minutes = timeNow.getMinutes()<10?"0"+timeNow.getMinutes():timeNow.getMinutes();
let seconds = timeNow.getSeconds()<10?"0"+timeNow.getSecondes():timeNow.getSeconds();
let time = `${hours}:${minutes}:${seconds}`;
h1.innerText = time;
},1000)
</script>
clearInterval
<button class="start">开始</button>
<button class="end">暂停</button>
<script>
let btn1 = document.querySelector(".start")
let btn2 = document.querySelector(".end")
let timer
//定时器的对象是window,需要全局声明才能通过函数调用
//如清除定时器的函数clearInterval调用定时器btn1里的setInterval
btn1.addEventListener("click",function(){
console.log("start")
timer = setInterval(() => {
console.log("hello")
},1000)
})
btn2.addEventListener("click",function(){
clearInterval(timer);
console.log("stop")
})
</script>
制作秒表(开始、暂停、结束)
<body>
<button class="start">开始</button>
<button class="pause">暂停</button>
<button class="end">结束</button>
<h1 class="time"></h1>
<script>
let start = document.querySelector(".start");
let pause = document.querySelector(".pause");
let end = document.querySelector(".end");
let time = document.querySelector(".time");
let minutes = 0;
let seconds = 0;
let ms = 0;//不是真正意义上的毫秒,实际是10ms
let timer = null;
time.innerHTML = `${minutes}:${seconds<10?"0"+seconds:seconds}:${ms<10?"0"+ms:ms}`;
start.addEventListener("click",function(){
clearInterval(timer);//清除抖动,防止连点“开始”,出现越点越快的情况(多个计数器参与计时)
timer = setInterval(() => {
if(seconds === 60){
seconds = 0;//先归零,不然会出现秒数为60的情况
++minutes;
}
if(ms === 100){
ms = 0;//重置ms,10毫秒为单位速度过快,有时还是会出现ms数为100
++seconds;
}
++ms;
time.innerHTML = `${minutes}:${seconds<10?"0"+seconds:seconds}:${ms<10?"0"+ms:ms}`;
},10)//10ms触发一次,1秒触发100次,实现ms逢100进1s
})
pause.addEventListener("click",function(){
clearInterval(timer);
})
end.addEventListener("click",function(){
clearInterval(timer);//没有暂停会导致计时器继续工作更新innerHtml,时间归零无效
minutes = 0;
seconds = 0;
ms = 0;
time.innerHTML = `${minutes}:${seconds<10?"0"+seconds:seconds}:${ms<10?"0"+ms:ms}`;
})
</script>
</body>
</html>
setTimeout
过多少秒后只执行一次
setTimeout(() => {
console.log("hello")
},3000)//3s后输出一次hello
3s后跳转到百度
<h1>3s后跳转到百度</h1>
<script>
setTimeout(() => {
location.href = "http://baidu.com"//跳转链接
},3000)
</script>
clearTimeout
停止setTimeout计时器
<button>停止</button>
<script>
let btn = document.querySelector("button")
let timer = null;
timer = setTimeout(() => {
console.log("hello")
},3000)
btn.addEventListener("click",function(){
clearTimeout(timer)
})
</script>
防抖与节流
防抖debounce
<style>
body{
height: 2000px;
}
</style>
</head>
<body>
<h1>window.onscroll事件</h1>
<script>
window.onscroll = function(){//鼠标滚轮触发事件
console.log("hello")
}
</script>
</body>
可见,鼠标上下滚了一遍,打印hello执行了160次,如果事件是其他的复杂逻辑,那就会耗费大量的性能,因此要防抖
<h1>window.onscroll事件</h1>
<script>
let timer = null;
window.onscroll = function(){
if(timer !== null){
clearTimeout(timer)
}
timer = setTimeout(() => {
console.log("hello")
timer = null
},500)
/*timer默认是null,则滚动后直接执行timer=setTimerout,但一执行该语句,timer马上就有了值,!=null
所以又会被clearTimeout停止计时。接着继续执行timer=setTimerout,又被停止计时。
只要鼠标一直处于滚动状态,计时器就会一直被暂停。直到鼠标不滚动了,最后一次clearTimeout
接着timer=setTimerout,这次因为已经不触发onscrll事件了,所以程序不会回到if判断
而是继续执行计时器,0.5s后输出hello
宏观上看,就是在鼠标滚动开始到停止滚动,0.5s后才输出一次hello
不会出现鼠标滚动就一直输出hello的情况,防抖*/
}
</script>
节流throttle
按照时间间隔触发事件
<h1>window.onscroll事件</h1>
<script>
let mark = true;
window.onscroll = function(){
if(mark){
setTimeout(() => {
console.log("hello");
mark = true;
},500);
}
mark = false;
/*if事件执行了但计时器还没执行,在计时器执行前mark=false,再滚动也不会执行新的计时器
0.5s后计时器执行,输出hello,mark=true
滚动鼠标又能执行if语句,一直往复
即管鼠标一直滚动,每0.5s才执行输出一次hello*/
}
</script>
练习
返回顶部
<style>
button{
position: fixed;
right: 100px;
bottom: 100px;
display: none;
}
body{
height: 2000px;
}
</style>
<body>
<h1>hello world</h1>
<button>↑</button>
<script>
let btn = document.querySelector("button")
btn.onclick = function(){
window.scrollTo(0,0)//横向纵向滚动条位置为最左边和最上边
}
let timer = null;
window.onscroll = function(){
if(timer !== null){
clearTimeout(timer);
}
timer = setTimeout(() => {
console.log("计数器");
//document.documentElement.scrollTop滚动条距离顶部的距离
if(document.documentElement.scrollTop > 0){
btn.style.display = "block";
}else{
btn.style.display = "none";
timer = null;
}
},500)
}
</script>
</body>
</html>
改进,利用闭包封装防抖算法
<script>
let btn = document.querySelector("button");
btn.onclick = function(){
window.scrollTo(0,0)
}
function debounce(fn){//闭包的意义在于把防抖的算法和业务算法区分开来
let timer = null;
function eventFun(){
if(timer !== null){
clearTimeout(timer);
}
timer = setTimeout(() => {
//业务逻辑在这,用一个函数fn表示
fn();
timer = null;
},500)
}
return eventFun;
}
window.onscroll = debounce(() => {//把业务逻辑传给fn
console.log("计数器");
//document.documentElement.scrollTop滚动条距离顶部的距离
if(document.documentElement.scrollTop > 0){
btn.style.display = "block";
}else{
btn.style.display = "none";
timer = null;
}
});
</script>
把防抖改成节流
<script>
let btn = document.querySelector("button");
btn.onclick = function(){
window.scrollTo(0,0)
}
function throttle(fn){
let mark = true;
return function(){
if(mark){
setTimeout(() => {
fn();
mark = true;
},500)
}
mark = false;
}
}
window.onscroll = throttle(() => {
console.log("计数器");
if(document.documentElement.scrollTop > 0){
btn.style.display = "block";
}else{
btn.style.display = "none";
timer = null;
}
});
</script>