今天,我们要实现的是一个超级小的demo,倒计时的简单实现,但是其中遇到的定时器的叠加问题,值得思考,所以写了这一篇文章。本人小白一个,多有不足,欢迎交流,共同进步。

HTML+CSS部分

这里的东西,不做过多的赘述哈,文末会有完整的源码哦。

 <style type="text/css">#box {width: 100px;height: 100px;line-height: 100px;font-size: 40px;margin: 30px auto;border: solid 4px black;text-align: center;}input {display: block;margin: 0 auto;}</style>
  <div id="box">5</div><input type="button" name="btn" id="startbtn" value="开始" /><input type="button" name="btn" id="stopbtn" value="停止" />

JS部分

当前的状态下,未添加任何的JS代码,效果是:

现在开始梳理一下思路哈。

我们要做的就是给开始按钮添加一个定时器,并且让上方的数字开始减少,而停止就是清除定时器最后数字恢复初始状态。

  1. 获取页面节点

    var boxObj = document.querySelector('#box');var startObj = document.querySelector('#startbtn');var stopObj = document.querySelector('#stopbtn');
  1. 获取页面中数字,并作为初识值

现在要获取页面中的数字,不仅仅是待会执行减减操作时的初始值,再开始点击事件结束之后,我们需要把页面中的数值,重新变为初始状态。所以这一步是很有必要的。

var initVal = boxObj.innerHTML;
  1. 相对的按钮设置点击事件

重点就在这里,本来案例来说,我们只需要设置相应的定时器,让数字减少就够了,但是,当我设置后发现情况不对。

正常思路:假设单纯设置定时器,那就是当数字缩减到-1的时候结束并清除定时器,使页面中的数字恢复初始值。(如果是0的话,判断条件就到0,这样就倒计时不到0了)。

代码应该如下:

<script>// 首先获取页面节点var boxObj = document.querySelector('#box');var startObj = document.querySelector('#startbtn');var stopObj = document.querySelector('#stopbtn');//2 获取页面中的数字,作为初始值,最后倒计时完了,还得是初始值var initVal = boxObj.innerHTML;// 绑定点击事件var times;startObj.onclick = function () {times = setInterval(function () {// 获取当前的数字var num = boxObj.innerHTML;// 执行减减操作num--;// 再扔回去boxObj.innerHTML = num;//判断停止的条件if (num == -1) {//清楚定时器clearInterval(times);//变为初始值boxObj.innerHTML = initVal;}}, 1000)}
</script>

情况发生

但是,就现在开始的点击,就发现了问题的所在,那就是,当我们点击开始按钮的时候,倒计时就开始了,但是,当我们再倒计时没有结束的时候,再次点击,多次点击开始按钮的时候,发现,一直循环倒计时。这就是典型的定时器堆叠现象。

解决方法

我们给接收定时器的times一个判断,当点击事件发生的时候,如果times有不为0,Nan,Null,undefined,'空字符串'的情况,就直接用return结束代码的执行,这样我们多次点击的时候,就会首先判断,如果有了就不会开启新的定时器。

注意:点击事件开始的时候就去创建一个判断,这是很好的操作,但是,如果我们第一次点击,执行代码时,times的状态就是true了,当我们--操作结束之后,想要再次点击的时候,发现无法点击了,这就是因为第12行的判断,所以再定时器结束条件中,应重置times的状态。

<script>// 首先获取页面节点var boxObj = document.querySelector('#box');var startObj = document.querySelector('#startbtn');var stopObj = document.querySelector('#stopbtn');//2 获取页面中的数字,作为初始值,最后倒计时完了,还得是初始值var initVal = boxObj.innerHTML;// 绑定点击事件var times;startObj.onclick = function () {//判断时候有定时器的存在了if (times) return;times = setInterval(function () {// 获取当前的数字var num = boxObj.innerHTML;// 执行减减操作num--;// 再扔回去boxObj.innerHTML = num;//判断停止的条件if (num == -1) {//清除定时器clearInterval(times);//这一句是为了在结束的时候
//此时,定时器的状态应该是true,如果不重新设置定时器的状态
//就会进入第12行的if中去,也就不再有新的定时器执行--操作了times = null;boxObj.innerHTML = initVal;}}, 1000)}
</script>

结束按钮大有不同

本来来说,点击停止就是简单的清除定时器,而我们一开始也是这样操作的。

    // 点击停止则暂停执行stopObj.onclick = function () {clearInterval(times);}

但是,我们发现,没有办法点击开始按钮了,这是因为,我们点击暂停的时候,times定时器被我们强制结束掉了,但是现在结束的状态时true,又是第12行,这句话,导致不会进行继续了,所以,在点击结束的时候,也应该设置times的状态为null,从而进入定时器的函数体。

疑惑

笔者一开始很疑惑,当我们点击停止之后,页面停止在--操作的数字,假设是3,但是当我们点击开始的时候,是怎么从3开始,并接着继续的呢。后来我才明白。

我们无论--操作到数字几,只要设置了times为null,他就会进入第39行的定时器函数体中,而我们的第一条语句就是获取当前页面的数字,所以减减进行到多少都没有关系。

源码

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><style type="text/css">#box {width: 100px;height: 100px;line-height: 100px;font-size: 40px;margin: 30px auto;border: solid 4px black;text-align: center;}input {display: block;margin: 0 auto;}</style>
</head>
<body>
<div id="box">5</div>
<input type="button" name="btn" id="startbtn" value="开始"/>
<input type="button" name="btn" id="stopbtn" value="停止"/>
<script>// 首先获取页面节点var boxObj = document.querySelector('#box');var startObj = document.querySelector('#startbtn');var stopObj = document.querySelector('#stopbtn');//2 获取页面中的数字,作为初始值,最后倒计时完了,还得是初始值var initVal = boxObj.innerHTML;// 绑定点击事件var times;startObj.onclick = function () {//判断时候有定时器的存在了if (times) return;times = setInterval(function () {// 获取当前的数字var num = boxObj.innerHTML;// 执行减减操作num--;// 再扔回去boxObj.innerHTML = num;//判断停止的条件if (num == -1) {//清除定时器clearInterval(times);//这一句是为了在结束的时候//此时,定时器的状态应该是true,如果不重新设置定时器的状态//就会进入第12行的if中去,也就不再有新的定时器执行--操作了times = null;boxObj.innerHTML = initVal;}}, 1000)}// 点击停止则暂停执行stopObj.onclick = function () {clearInterval(times);// times = null;}</script>
</body>
</html>

Js定时器倒计时及堆叠问题解析(附源码)相关推荐

  1. php图片动画源码,JavaScript_jQuery插件ImageDrawer.js实现动态绘制图片动画(附源码下载),ImageDrawer.js是一款可以实现动 - phpStudy...

    jQuery插件ImageDrawer.js实现动态绘制图片动画(附源码下载) ImageDrawer.js是一款可以实现动态绘制图片动画的jQuery插件.通过ImageDrawer.js插件,你可 ...

  2. 基于Node.js自我展示博客网站-计算机毕设 附源码231547

    自我展示博客网站的设计与实现 摘 要 个人博客网站是当今网络的热点,个人博客技术的出现使得每个人可以零成本.零维护地创建自己的网络媒体,Blog站点所形成的网状结构促成了不同于以往社区的Blog文化, ...

  3. 从零开始用js手写飞机大战全过程(附源码)

    plane game 前言 此文章帮助初学者学习制作一个简单小游戏 目标 利用css,html,js制作出飞机大战的简略版 前置准备 1. 绝对定位与相对定位 这里除了背景都设置为绝对定位,使飞机和敌 ...

  4. 基于STM32F103系列单片机四路定时器电机编码器模式配置过程附源码

    这篇文章记录了当时在实习期间做了一个四驱的移动平台,通过四路PWM控制电机转速,8个IO口控制电机方向,然后通过与电机同轴的编码器反馈转速,从而实现电机的闭环PID控制方法. 本文用的是基于STM32 ...

  5. HTML,JS和CSS实现减肥周期计算(附源码)

    「原理」 体内每1克脂肪提供9.46千卡的热量,每消耗9460千卡热量=消耗1000克(1公斤)脂肪.也就是说只要计算出每天的热量消耗就可以计算出具体的天数了! 『计算 - 第一步:基础代谢值(BMR ...

  6. js逆向之腾讯漫画《附源码》

    想看漫画但是没有VIP,想要爬取付费漫画:这是不可能滴 搜索到的程序要么是通过自动化,要么是代码有点老旧:互联网总是更新发展的嘛. 自动化实在是太慢了,一个520章的漫画得下载一天一夜这不符合搞爬虫的 ...

  7. html div初始隐藏点击可见_3种CSS3移动手机隐藏菜单UI界面代码解析/附源码下载...

    这是一款效果非常酷的jQuery和CSS3移动手机隐藏菜单UI界面设计.这个UI设计共有三种不同的打开隐藏菜单的效果,分别为滑动显示,Material Design风格效果和展开式效果. 使用方法 H ...

  8. 纯js 别踩白块游戏解析与源码

    (一)别踩白块 1.考虑游戏中有哪些对象,属性和方法?    别踩白块游戏仔细想想如果非要对象的话,游戏显示界面可以算是一个对象,下滑的区域算一个对象(每个小方格算对象的属性对象吧) 2.这里主要要思 ...

  9. leaflet 结合 d3.js 实现 geojson 数据地形剖面分析(附源码下载)

    前言 leaflet 入门开发系列环境知识点了解: leaflet api文档介绍,详细介绍 leaflet 每个类的函数以及属性等等 leaflet 在线例子 leaflet 插件,leaflet ...

最新文章

  1. R语言分类模型:逻辑回归模型LR、决策树DT、推理决策树CDT、随机森林RF、支持向量机SVM、Rattle可视化界面数据挖掘、分类模型评估指标(准确度、敏感度、特异度、PPV、NPV)
  2. 管理类业务系统菜单部分美化经验分享,把所有好的东西拿过来拼凑并不容易能形成整体的效果...
  3. python可以干嘛知乎-Python到底可以干什么?老男孩Python视频教程
  4. 云计算与springCloud概念上的区别
  5. 【ZOJ - 2949】Coins of Luck (概率dp,期望)
  6. 数据库事务(Database Transaction)
  7. FastDFS+Nginx+Module
  8. [转载] log4j-over-slf4j与slf4j-log4j12共存stack overflow异常分析
  9. 2016年安防企业如何因势而动 顺势而为
  10. oracle timesten tt的启动与停止
  11. ubuntu虚拟机使用笔记——9、vmware卸载,重新安装ubuntu,重安后不能共享文件
  12. 软件系统服务器改造方案,并实施系统软件国产化改造方案 审计署.doc
  13. U盘因为有写保护,不能格式化,该怎么办
  14. 让你5分钟明白美国金融危机爆发的原因!
  15. 解决支付订单,重复提交问题!
  16. 【面试题】网易互娱(游戏)2021校园招聘在线笔试 - 服务端开发工程师[文件系统]
  17. 源支付聚合免签支付系统
  18. centos6 安装redis
  19. android 设备序列号_如何查找您的Android设备的序列号
  20. 【sfu】network线程和主线程

热门文章

  1. Java中String转为Long
  2. java基础:注解的定义与使用
  3. OpenGL学习——着色器
  4. 解决:python爬取豆瓣电影遇到的KeyError: 'subject_collection_items'错误
  5. Java中的数据文件
  6. 《微波原理与技术》学习笔记2传输线理论-传输线方程的推导与求解
  7. DTD和XSD的区别
  8. C/C++文件输入输出(详细介绍)
  9. 微信公众号获取openid(java后端+html实现)
  10. 四阶及以上魔方公式技巧大全