JavaScript学习笔记 06、DOM元素—③定时器与延时器
@[toc]
前言
本篇博客是关于javascript中定时器与延时器,若文章中出现相关问题,请指出!
所有博客文件目录索引:博客目录索引(持续更新)
一、定时器(√)
1.1、介绍定时器与清除定时器方法(含案例)
设置定时器:
setInterval()
js中我们通过使用setInterval()
函数来实现定时功能!
函数参数
:
hander
:指的是你要调用的函数(匿名函数或者指定函数对象)。timeout
:间隔时间,以毫秒为单位,1000就表示1秒。
返回值
:此返回值intervalID
是一个非零数值(number),用来标识通过setInterval()
创建的计时器,这个值可以用来作为clearInterval()
的参数来清除对应的计时器 (使用一个全局变量来进行存储这个值)。
案例:
<body>
<p id="m_p">0</p>
<script>
var m_p = document.getElementById("m_p");
var a = 0;
//方式一:在函数中添加一个匿名函数
// setInterval(function () {
// a++;
// m_p.innerText = a;
// }, 1000);
//方式二:通过传入一个指定函数
//①定义函数
function addA() {
a++;
m_p.innerText = a;
}
//②将指定函数传入到setInterval()中
setInterval(addA, 1000);
</script>
</body>
清除定时器:clearInterval()
- 需要传入指定定时器生成的ID,执行该函数时就会删除指定ID的定时器。
测试demo:
<style>
* {
margin: 0;
padding: 0;
}
p {
margin-left: 30px;
}
</style>
<body>
<p id="m_p">0</p>
<button>清除定时器</button>
<script>
var m_p = document.getElementById("m_p");
var a = 0;
//方式一:在函数中添加一个匿名函数
var intervalID = setInterval(function () {
a++;
m_p.innerText = a;
}, 1000);
//清除定时器
var m_button = document.getElementsByTagName("button")[0];
m_button.onclick = function () {
//清除定时器,传入指定定时器的ID
clearInterval(intervalID);
};
</script>
</body>
1.2、解决按钮点击时设置定时器setInterval()的小问题
问题提出
问题描述:当我们在点击按钮事件下设置定时器,若是我们多次点击按钮,实际上就会创建多个定时器就会按照对应的时间间隔不断执行!此时作用效果就会叠加,原本1s进行+1的,连续点了多次创建了多个定时器就会1s连续加多次!
<body>
<p id="m_p">0</p>
<button>添加定时器</button>
<script>
var m_p = document.getElementById("m_p");
var a = 0;//p标签起始值
var intervalID;//使用一个全局变量来保存ID
var m_button = document.getElementsByTagName("button")[0];
//按钮绑定单击事件
m_button.onclick = function () {
intervalID = setInterval(function () {
a++;
m_p.innerText = a;
}, 1000);
};
</script>
</body>
解决方案
解决方案应该有两种:①一旦点击了定时器,该按钮就锁定,无法点击了。②不锁定按钮方式,每点击一次就先清除上一次定时器!
这里的话就演示第二种方式:
<style>
* {
margin: 0;
padding: 0;
}
p {
margin-left: 30px;
}
</style>
<body>
<p id="m_p">0</p>
<button>添加定时器</button>
<script>
var m_p = document.getElementById("m_p");
var a = 0;//p标签起始值
var intervalID;//使用一个全局变量来保存ID
var m_button = document.getElementsByTagName("button")[0];
m_button.onclick = function () {
clearInterval(intervalID);//初次调用intervalID为undefined,传入清除函数也不会报异常
intervalID = setInterval(function () {
a++;
m_p.innerText = a;
}, 1000);
};
</script>
</body>
1.3、实际案例(设置与删除定时器)
需求:使用两个按钮来进行添加与删除定时器,定时器需要每秒对p标签中的值+1。
源码:
<style>
* {
margin: 0;
padding: 0;
}
p {
margin-left: 30px;
}
</style>
<body>
<p id="m_p">0</p>
<button>添加定时器</button>
<button>删除定时器</button>
<script>
var m_p = document.getElementById("m_p");
var a = 0;//p标签起始值
var intervalID;//使用一个全局变量来保存ID
var m_add_button = document.getElementsByTagName("button")[0];
var m_del_button = document.getElementsByTagName("button")[1];
//添加定时器按钮绑定单击事件
m_add_button.onclick = function () {
clearInterval(intervalID);//初次调用intervalID为undefined,传入清除函数也
intervalID = setInterval(function () {
a++;
m_p.innerText = a;
}, 1000);
};
//删除定时器按钮绑定单击事件
m_del_button.onclick = function () {
clearInterval(intervalID);
}
</script>
</body>
二、延时器(√)
介绍
与定时器大致相同,同样有设置与添加延时器!
语法:
- 设置延时器:
setTimeout()
,设置一个延时器,只有当指定时间到了之后会执行函数一次,不会再重复执行。 - 清除延时器:
clearTimeout()
,可以清除延时器,与clearInterval()大致相同同样需要传入对应的延时器ID。
示例
需求:点击添加延时器,2s后出现提示框;删除延时器即删除指定id的延时器。
<style>
* {
margin: 0;
padding: 0;
}
p {
margin-left: 30px;
}
</style>
<body>
<button>添加延时器</button>
<button>删除延时器</button>
<script>
var m_p = document.getElementById("m_p");
var timeoutID;//使用一个全局变量来保存ID
var m_add_button = document.getElementsByTagName("button")[0];
var m_del_button = document.getElementsByTagName("button")[1];
//添加延时器按钮绑定单击事件
m_add_button.onclick = function () {
//clearTimeout(timeoutID);//同样也需要删除之前的延时器
timeoutID = setTimeout(function () {
alert("2s后延时器触发了!")
}, 2000);
};
//删除定时器按钮绑定单击事件
m_del_button.onclick = function () {
clearTimeout(timeoutID);
}
</script>
</body>
三、认识异步
介绍异步
异步(asynchronous):不会阻塞CPU继续执行其他语句,当异步完成时,会执行"回调函数"。
- 重点:对于异步函数不会影响程序的正常执行。例如设置2s的定时器,并不会等待2秒后才执行下一条语句,而是正常往下进行执行!
其实定时器以及延时器的setXXX()
方法就是异步函数,其中传入的函数就是回调函数:
示例
需求:在点击按钮时,先设置延时器,其后面输出一条语句,看是否是先等待延时器等待2秒后执行回调函数以后再执行的console输出语句!
效果:对于异步函数,调用执行函数并不会妨碍其他程序的正常执行!
<body>
<button>添加延时器</button>
<script>
var timeoutID;//使用一个全局变量来保存ID
var m_add_button = document.getElementsByTagName("button")[0];
//添加延时器按钮绑定单击事件
m_add_button.onclick = function () {
timeoutID = setTimeout(function () {
alert("2s后延时器触发了!")
}, 2000);
console.log("changlu❤林儿");
};
</script>
</body>
四、定时器实现动画
4.1、js实现动画(不推荐)
需求:使用js来实现盒子的移动。从40px -> 600px,2s。
弊端:若是仅仅通过使用js来实现动画,这是十分麻烦的,例如你想要2s实现的一个动画,你需要去计算每秒其移动多少距离,每秒移动多少次,这需要进行大量计算,并且若是你还想设置返回动画,那就还需要进行更多的逻辑判断。
- 现在有许多的一些三方库给我们封装好,如jquery等。更好的方式还是
js+css动画
来进行配合使用!
<style>
* {
margin: 0;
padding: 0;
}
div.box {
width: 100px;
height: 100px;
border: 1px solid #000;
background-color: orange;
margin: 40px;
}
</style>
<body>
<div class="box" id="box"></div>
<script>
var m_box = document.getElementById("box");
var left = 30;
m_box.onclick = function () {
var myInterval = setInterval(function () {
left += 2;
//设置盒子停止时机
if (left >= 600) {
//指定到600px停止,清除定时器
clearInterval(myInterval);
}
m_box.style.marginLeft = left + "px";
}, 7);
//一秒中执行50次,预计设想2秒移动 => 移动距离560px。
//1s就是280px,每次移动2px,那就是1s移动140次;1分钟1000毫秒,那就是设置7ms一次。
};
</script>
</body>
4.2、js+css配合实现动画
实现盒子左右移动(过渡+基本判断)
需求:我们点击一个按钮,让盒子移动到右边,再点击一下盒子移动到左边。
分析:
- 使用css动画来实现过渡效果:
m_box.style.transition = "all 2s linear 0s";
。 - 对于点击从左到右、从右到左通过js来进行控制。(通过判断postion属性来进行操作)
源码:
<style>
* {
margin: 0;
padding: 0;
}
div.box {
position: absolute;
top: 30px;
left: 40px;
width: 100px;
height: 100px;
border: 1px solid #000;
background-color: orange;
}
</style>
<body>
<button>点我移动</button>
<div class="box" id="box"></div>
<script>
var m_button = document.getElementsByTagName("button")[0];
var m_box = document.getElementById("box");
var position = 0;//0:左边,1:右边
m_button.onclick = function () {
//1、使用css动画来实现过渡效果
m_box.style.transition = "all 2s linear 0s";
//2、js来编程进行左右的移动效果
if (position == 0) {
m_box.style.left = "1000px";
position = 1;
} else if (position == 1) {
m_box.style.left = "40px";
position = 0;
}
};
</script>
</body>
案例出现问题(通过函数节流解决)
问题抛出
问题说明:虽说上面实现了通过按钮点击进行盒子的左右移动效果,但是若是我们在该盒子移动过程中多次去点击按钮,就会出现下面情况。
- 按理说是要先移动到右边,再进行移动到左边,可是中途进行点击就会一下子立马又向左移,我们如何来实现向左或向右完整执行2s再进行相反的移动呢?
解决方案:使用函数节流
函数节流:该名词是这样定义的,当一个函数执行一次后,只有大于设定的执行周期后才允许执行第二次。
固定模板:
var lock = true;//默认为true,表示开锁,允许进行下一步操作了
function 指定需要函数节流函数(){
//如果当前为false(表示已经上锁),不往下执行
if(!lock) return; //函数结束
//关锁
lock = false;
xxx; //一些业务操作
//使用延时器来等待2秒后开锁(时间根据指定情况来定),到时间了就开锁
setTimeout(function(){
lock = true;
},2000);
}
优化上面的左右移动案例:只有动画执行完之后点击才有效(通过使用上方模板)
<style>
* {
margin: 0;
padding: 0;
}
div.box {
position: absolute;
top: 30px;
left: 40px;
width: 100px;
height: 100px;
border: 1px solid #000;
background-color: orange;
}
</style>
<body>
<button>点我移动</button>
<div class="box" id="box"></div>
<script>
var m_button = document.getElementsByTagName("button")[0];
var m_box = document.getElementById("box");
var position = 0;//0:左边,1:右边
//1、锁:true为开锁,false为上锁
var lock = true;
m_button.onclick = function () {
//2、若是lock为false,表示上锁,直接退出函数
if (!lock) return;
//3、若是lock为true表示现在开着锁,继续向下执行,这里设置为false,表示此时在执行业务所以上锁
lock = false;
m_box.style.transition = "all 2s linear 0s";
if (position == 0) {
m_box.style.left = "1000px";
position = 1;
} else if (position == 1) {
m_box.style.left = "40px";
position = 0;
}
//4、使用延时器,由于动画是2s,所以这里设置2s后开锁!
setTimeout(function () {
lock = true;
}, 2000);
};
</script>
</body>
实际案例
1、无缝连续滚动特效
效果与分析
需求:制作一个展示栏,展示栏中有多张图片(这里使用小盒子来替代),会不断进行连续滚动。当鼠标触碰进盒子就会暂停,离开盒子就会继续连续滚动。
思路分析:
首先是结构分析:外层使用了一个盒子,内部是ul的列表(使用了左浮动)。其中其中的div外盒子设置宽度为300px,但是为了让li元素都在一行上,就需要设置ul的宽度为1300px。
<div class="box">
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
</ul>
</div>
我们来剖析一下原理:
我们把div的overflow: hidden
取消,你就可以看到真面目了,里面有两倍的盒子(方便每一个盒子都能被看到),通过使用定时器来实现整个盒子的移动,并没有使用css的动画属性,当定时器中盒子到达指定left位置时,就重新设置left=0,重新进行循环进行。
额外说明的是:本次案例添加了两个事件,一个是鼠标移入,另一个是鼠标移出,分别是对定时器的设置与清除。
源码
<style>
* {
margin: 0;
padding: 0;
}
div.box {
position: relative;
width: 300px;
height: 62px;
overflow: hidden;
border: 1px solid #000;
margin: 20px auto;
}
div.box ul {
position: absolute;
/*0一直到-330px表示一趟结束 */
left: 0;
list-style: none;
/* 设置内部的ul宽度大一些,来支撑原本内部元素的长度 */
width: 1300px;
}
div.box li {
float: left;
height: 60px;
width: 80px;
border: 1px solid #000;
text-align: center;
line-height: 60px;
margin-right: 10px;
background-color: orange;
}
div.box li:nth-child(1) {
background-color: red;
}
div.box li:nth-child(2) {
background-color: blue;
}
div.box li:nth-child(3) {
background-color: green;
}
div.box li:nth-child(4) {
background-color: gold;
}
div.box li:nth-child(5) {
background-color: goldenrod;
}
div.box li:nth-child(6) {
background-color: orange;
}
div.box li:nth-child(7) {
background-color: gray;
}
</style>
<body>
<div class="box">
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
</ul>
</div>
<script>
var m_ul = document.getElementsByTagName("ul")[0];
//复制一份待移动的多个小盒子(方便每个盒子都能够预览到)
m_ul.innerHTML += m_ul.innerHTML;
//全局变量:ul左边距离
var l = 0;
//全局变量:定时器的ID号
var inervalID
//创建定时器
function setShowInterval() {
clearInterval(inervalID);//一定要记得清除事件
//设置定时器
inervalID = setInterval(function () {
l -= 4;
if (l <= -850) {
l = 0;
}
m_ul.style.left = l + "px";
}, 20);
}
//初始化时要创建定时器
setShowInterval();
//鼠标移入与移除事件
//为ul设置鼠标移入事件:定时器停止
m_ul.onmouseenter = function () {
clearInterval(inervalID);
}
//为ul设置鼠标移出事件:设置定时器
m_ul.onmouseleave = function () {
setShowInterval();
}
</script>
</body>
2、跑马灯轮播图(左右翻图)
实际原理与案例1的无缝连续滚动相同,只不过这里将第一个图片多复制了一份到后面。
使用到的知识点如:
- 克隆节点+点击事件,css+js配合实现动画效果。
- 对于前后切换图片(快速无痕切换),需要将transication属性在
none
、all .5s ease 0s
两者间进行切换。 - 函数节点(控制动画效果能够顺利完成)。
效果展示:点击左右按钮实现图片翻页
源码:
<style>
* {
margin: 0;
padding: 0;
font-size: large;
font-weight: bolder;
}
div.box {
position: relative;
width: 350px;
height: 230px;
margin: 20px auto;
border: 1px solid #000;
overflow: hidden;
}
div.box ul {
list-style: none;
/* 350*5=1750 */
width: 1750px;
position: absolute;
left: 0;
}
div.box ul li {
float: left;
}
img {
width: 350px;
height: 230px;
}
a {
text-decoration: none;
position: absolute;
width: 30px;
height: 30px;
border-radius: 15px;
background-color: rgba(255, 255, 255, .5);
text-align: center;
line-height: 30px;
}
a:nth-of-type(1) {
top: 50%;
left: 0;
margin-top: -15px;
}
a:nth-of-type(2) {
top: 50%;
right: 0;
margin-top: -15px;
}
</style>
<body>
<div class="box">
<ul>
<li><img src="./images/img_01.jpg" alt=""></li>
<li><img src="./images/img_02.jpg" alt=""></li>
<li><img src="./images/img_03.jpg" alt=""></li>
<li><img src="./images/img_04.jpg" alt=""></li>
</ul>
<a href="javascript:;"><</a>
<a href="javascript:;">></a>
</div>
<script>
//宽为230px
//两个按钮节点
var firstA = document.getElementsByTagName("a")[0];
var secondA = document.getElementsByTagName("a")[1];
//ul元素
var myul = document.getElementsByTagName("ul")[0]
var currentImgPos = 0;//表示第几张图片
//为ul结尾添加第一张图
myul.appendChild(document.getElementsByTagName("li")[0].cloneNode(true));
//用于函数节点操作
var lock = true;
//给左按钮绑定单击事件
firstA.onclick = function () {
if (!lock) return;
lock = false;
myul.style.transition = "all .5s ease 0s";
currentImgPos++;
//若是已经到达了第五张图,通过使用延时器来快速回到原本位置
if (currentImgPos == 4) {
//使用延时器恢复原来的过渡效果
setTimeout(function () {
myul.style.transition = "none";
currentImgPos = 0;
myul.style.left = 0 + "px";
}, 500);
}
myul.style.left = -currentImgPos * 350 + "px";
//设置0.5s(与切换一张图片相同时长释放锁)
setTimeout(function () {
lock = true;
}, 500)
};
// 点击右边按钮
secondA.onclick = function () {
if (!lock) return;
lock = false;
//一旦图片是第一张往前移
if (currentImgPos == 0) {
// 快速移动到最后一张图片上
myul.style.transition = "none";
myul.style.left = -4 * 350 + "px";
//这个延时器就设置为0s,在其后进行向前移动效果(含过渡)
setTimeout(function () {
myul.style.transition = "all .5s ease 0s";
currentImgPos = 3;
myul.style.left = -currentImgPos * 350 + "px";
}, 0);
} else {
//正常向前移动
currentImgPos--;
myul.style.left = -currentImgPos * 350 + "px";
}
//设置0.5s(与切换一张图片相同时长释放锁)
setTimeout(function () {
lock = true;
}, 500)
}
</script>
</body>
3、呼吸轮播图
分析:同样也是轮播图,通过点击左右按钮的方式来进行淡入淡出的。想要制作出这类效果,需要将多张图片全部堆叠在一起,初始三张图片设置透明度为0,另外一张透明度为1。之后对透明度参数设置过渡效果实现!
源码:
<style>
* {
margin: 0;
padding: 0;
font-size: large;
font-weight: bolder;
}
div.box {
position: relative;
width: 350px;
height: 230px;
margin: 20px auto;
border: 1px solid #000;
/* overflow: hidden; */
}
div.box ul {
list-style: none;
/* 350*5=1750 */
width: 1750px;
position: absolute;
left: 0;
}
div.box ul li {
position: absolute;
left: 0;
top: 0;
/* 透明度为0 */
opacity: 0;
transition: all 1s linear 0s;
}
div.box ul li:nth-child(1) {
/* 透明度为1 */
opacity: 1;
}
img {
width: 350px;
height: 230px;
}
a {
text-decoration: none;
position: absolute;
width: 30px;
height: 30px;
border-radius: 15px;
background-color: rgba(255, 255, 255, .5);
text-align: center;
line-height: 30px;
}
a:nth-of-type(1) {
top: 50%;
left: 0;
margin-top: -15px;
}
a:nth-of-type(2) {
top: 50%;
right: 0;
margin-top: -15px;
}
</style>
<body>
<div class="box">
<ul>
<li><img src="./images/img_01.jpg" alt=""></li>
<li><img src="./images/img_02.jpg" alt=""></li>
<li><img src="./images/img_03.jpg" alt=""></li>
<li><img src="./images/img_04.jpg" alt=""></li>
</ul>
<a href="javascript:;"><</a>
<a href="javascript:;">></a>
</div>
<script>
//宽为230px
//两个按钮节点
var firstA = document.getElementsByTagName("a")[0];
var secondA = document.getElementsByTagName("a")[1];
//li元素
var lists = document.getElementsByTagName("li");
var pos = 0;//表示当前照片的位置
//用于函数节点操作
var lock = true;
//给左按钮绑定单击事件
firstA.onclick = function () {
if (!lock) return;
lock = false;
//老图淡出
lists[pos].style.opacity = 0;
pos++;
if (pos > 3) {
pos = 0;
}
//新图淡入
lists[pos].style.opacity = 1;
setTimeout(function () {
lock = true;
}, 1000);
};
//给右按钮绑定单击事件
secondA.onclick = function () {
if (!lock) return;
lock = false;
//老图淡出
lists[pos].style.opacity = 0;
pos--;
if (pos < 0) {
pos = 3;
}
//新图淡入
lists[pos].style.opacity = 1;
setTimeout(function () {
lock = true;
}, 1000);
};
</script>
</body>
- 点赞
- 收藏
- 关注作者
评论(0)