深入理解定时器系列第三篇——定时器应用(时钟、倒计时、秒表和闹钟)

前面的话

  本文属于定时器的应用部分,分别用于实现与时间相关的四个应用,包括时钟、倒计时、秒表和闹钟。与时间相关需要用到时间和日期对象Date,详细情况移步至此

时钟

  最简单的时钟制作办法是通过正则表达式exec()方法,将时间对象的字符串中的时间部分截取出来,使用定时器刷新即可

<div id="myDiv"></div>
<script>
myDiv.innerHTML = /\d\d:\d\d:\d\d/.exec(new Date().toString())[0];
setInterval(function(){
    myDiv.innerHTML = /\d\d:\d\d:\d\d/.exec(new Date().toString())[0];
},500);
</script>

倒计时

【1】简易倒计时

  简易倒计时就是每1s通过setInterval将设置的时间减去1来达到要求

<div id="myDiv">
    <label for="set"><input type="number" id="set" step="1" value="0">秒</label>
    <button id="btn">确定</button>
    <button id="reset">重置</button>
</div>
<script>
var timer;
reset.onclick = function(){
    history.go();
}
btn.onclick = function(){
    if(timer) return;
    set.setAttribute(‘disabled‘,‘disabled‘);
    timer = setInterval(function(){
        if(Number(set.value) === 0){
            clearInterval(timer);
            timer = 0;
            set.removeAttribute(‘disabled‘);
            return;
        }
        set.value = Number(set.value) - 1;
    },1000);
}
</script>

【2】精确倒计时

  由定时器的运行机制,我们知道每间隔1000ms去改变时间的作法并不可靠。更精确地做法,应该是与系统的运行时间作为参照,倒计时的时间变化与系统的时间变化同步,达到精确倒计时的效果 

  [注意]此部分中,需要通过取模运算除法运算进行时、分、秒的计算,详细情况移步至此

<div id="myDiv">
    <label for="hour"><input type="number" id="hour" min="0" max="23" step="1" value="0" />时</label>
    <label for="minute"><input type="number" id="minute" min="0" max="59" step="1" value="0" />分</label>
    <label for="second"><input type="number" id="second" min="0" max="23" step="1" value="0" />秒</label>
    <button id="btn">确定</button>
    <button id="reset">重置</button>
</div>
<script>
var timer;
//输入限制
hour.onchange = function(){
    if(Number(this.value) !== Number(this.value)) this.value = 0;
    if(this.value > 23) this.value = 23;
    if(this.value < 0) this.value = 0;
}
second.onchange = minute.onchange = function(){
    if(Number(this.value) !== Number(this.value)) this.value = 0;
    if(this.value > 59) this.value = 59;
    if(this.value < 0) this.value = 0;
}
reset.onclick = function(){
    history.go();
}
btn.onclick = function(){
    if(timer) return;
    for(var i = 0; i < 3; i++){
        myDiv.getElementsByTagName(‘input‘)[i].setAttribute(‘disabled‘,‘disabled‘);
    }
    //原始储存值
    var setOri = hour.value*3600 + minute.value*60 + second.value*1;
    //原始系统时间值
    var timeOri = (new Date()).getTime();
    //现在所剩时间值
    var setNow;
    cancelAnimationFrame(timer);
    timer = requestAnimationFrame(function fn(){
        //当前系统时间值
        var timeNow = (new Date()).getTime();
        //使系统时间的差值与设置时间的差值相等,来获得正常的时间变化
        setNow = setOri - Math.floor((timeNow - timeOri)/1000);
        hour.value = Math.floor((setNow%86400)/3600);
        minute.value = Math.floor((setNow%3600)/60);
        second.value = Math.floor(setNow%60);
        timer = requestAnimationFrame(fn);
        if(setNow==0){
            cancelAnimationFrame(timer);
            timer = 0;
            btn.innerHTML = ‘计时结束‘;
            for(var i = 0; i < 3; i++){
                myDiv.getElementsByTagName(‘input‘)[i].removeAttribute(‘disabled‘);
            }
            setTimeout(function(){
                btn.innerHTML = ‘确定‘;
            },1000)
        }

    })
}
</script>

秒表

【1】简易秒表

  秒表与倒计时的思路相同,相比而言,更加简单。每间隔100ms增加100ms即可

<div id="myDiv">
    <label for="set"><input id="set" value="0"></label>
    <button id="btn">开始</button>
    <button id="reset">重置</button>
</div>
<script>
var timer;
var con = ‘off‘;
var num = 0;
reset.onclick = function(){
    history.go();
}
btn.onclick = function(){
    if(con === ‘off‘){
        set.setAttribute(‘disabled‘,‘disabled‘);
        con = ‘on‘;
        btn.innerHTML = ‘暂停‘;
        timer = setInterval(function(){
            num+= 100;
            var minute = Math.floor(num/1000/60);
            var second = Math.floor(num/1000);
            var ms = Math.floor(num%1000)/100;
            set.value = minute + ‘ : ‘ + second + ‘ . ‘ + ms;
        },100);
    }else{
        clearInterval(timer);
        con = ‘off‘;
        btn.innerHTML = ‘开始‘;
    }
}
</script>

【2】精确秒表

  与倒计时类似,使用计时器的时间间隔作为时间变化的参照是不准确的。更精确的做法,应该是使用系统的时间变化作为秒表的变化的参照

<div id="myDiv">
    <label for="set"><input id="set" value="0"></label>
    <button id="btn">开始</button>
    <button id="reset">重置</button>
</div>
<script>
var timer;
var con = ‘off‘;
//ori表示初始的系统时间
var ori;
//dis表示当前运行时的秒数(动态)
var dis = 0;
//last储存暂停时的秒数(静态)
var last = 0;
reset.onclick = function(){
    history.go();
}
btn.onclick = function(){
    if(con === ‘off‘){
        set.setAttribute(‘disabled‘,‘disabled‘);
        con = ‘on‘;
        btn.innerHTML = ‘暂停‘;
        //保留已经走过的秒数的系统时间
        ori = (new Date()).getTime() - last;
        timer = requestAnimationFrame(function fn(){

            dis = (new Date()).getTime() - ori;
            cancelAnimationFrame(timer);
            timer = requestAnimationFrame(fn);
            var minute = Math.floor(dis/1000/60);
            var second = Math.floor(dis/1000);
            var ms = Math.floor(dis%1000);
            set.value = minute + ‘ : ‘ + second + ‘ . ‘ + ms;
        });
    }else{
        cancelAnimationFrame(timer);
        btn.innerHTML = ‘开始‘;
        con = ‘off‘;
        last = dis;
    }
}
</script>

闹钟

  闹钟其实就是在时钟的基础上增加一个预定时间设置,闹钟设置需要将设置时间转换成距离1970年1月1日的毫秒数,然后再算出与当前时间的差值。随着当前时间的不断增加,当差值为0时,闹钟响起

<div id="myDiv"></div>
<div id="con">
    <label for="hour"><input type="number" id="hour" min="0" max="23" step="1" value="0" />时</label>
    <label for="minute"><input type="number" id="minute" min="0" max="59" step="1" value="0" />分</label>
    <label for="second"><input type="number" id="second" min="0" max="23" step="1" value="0" />秒</label>
    <button id="btn">确定</button>
    <button id="reset">重置</button>
</div>
<div id="show"></div>
<script>
var timer;
//所剩时间
var dis;
myDiv.innerHTML = /\d\d:\d\d:\d\d/.exec(new Date().toString())[0];
setInterval(function(){
    myDiv.innerHTML = /\d\d:\d\d:\d\d/.exec(new Date().toString())[0];
},100);
reset.onclick = function(){
    history.go();
}
btn.onclick = function(){
    //原始储存值
    var setOri = hour.value*3600 + minute.value*60 + second.value*1;
    //原始值转换为1970年的毫秒数
    var setMs = +new Date(new Date().toDateString()) + setOri*1000;
    //如果设置的时间早于当前时间,则设置无效
    if(setMs < +new Date()){
        return;
    }
    for(var i = 0; i < 3; i++){
        con.getElementsByTagName(‘input‘)[i].setAttribute(‘disabled‘,‘disabled‘);
    }
    cancelAnimationFrame(timer);
    timer = requestAnimationFrame(function fn(){
        //算出设置时间与当前时间的差值
        dis = Math.ceil((setMs - (new Date()).getTime())/1000);
        var showHour = Math.floor((dis%86400)/3600);
        var showMinute = Math.floor((dis%3600)/60);
        var showSecond = Math.floor(dis%60);
        timer = requestAnimationFrame(fn);
        show.innerHTML = ‘距离预定时间还有 ‘ + showHour + ‘小时 ‘ + showMinute + ‘分 ‘ + showSecond + ‘秒‘;
        //当差值为0时,时间到
        if(dis==0){
            cancelAnimationFrame(timer);
            btn.innerHTML = ‘时间到了‘;
            for(var i = 0; i < 3; i++){
                con.getElementsByTagName(‘input‘)[i].removeAttribute(‘disabled‘);
            }
            timer = setTimeout(function(){
                btn.innerHTML = ‘确定‘;
            },1000)
        }

    });
}
</script>

最后

  作为定时器来说,最麻烦的地方是定时器管理。如果,定时器只开启不关闭,则会造成定时器叠加效果,使得运行越来越快。所以,先关闭再启用定时器是一个好习惯

  上面四个应用加上之前的日历效果,基本囊括了关于日期和时间的应用。基本原理都类似,剩下的就是CSS美化和js代码优化问题

转载自:https://www.cnblogs.com/xiaohuochai/p/5777757.html

原文地址:https://www.cnblogs.com/create-and-orange/p/10849951.html

时间: 2024-08-06 18:21:02

深入理解定时器系列第三篇——定时器应用(时钟、倒计时、秒表和闹钟)的相关文章

深入理解BOM系列第三篇——定时器应用(时钟、倒计时、秒表和闹钟)

× 目录 [1]时钟 [2]倒计时 [3]秒表[4]闹钟 前面的话 本文属于定时器的应用部分,分别用于实现与时间相关的四个应用,包括时钟.倒计时.秒表和闹钟.与时间相关需要用到时间和日期对象Date,详细情况移步至此 时钟 最简单的时钟制作办法是通过正则表达式的exec()方法,将时间对象的字符串中的时间部分截取出来,使用定时器刷新即可 <div id="myDiv"></div> <script> myDiv.innerHTML = /\d\d:\

深入理解闭包系列第三篇——IIFE

× 目录 [1]实现 [2]用途 前面的话 严格来讲,IIFE并不是闭包,因为它并不满足函数成为闭包的三个条件.但一般地,人们认为IIFE就是闭包,毕竟闭包有多个定义.本文将详细介绍IIFE的实现和用途 实现 函数跟随一对圆括号()表示函数调用 //函数声明语句写法 function test(){}; test(); //函数表达式写法 var test = function(){}; test(); 但有时需要在定义函数之后,立即调用该函数.这种函数就叫做立即执行函数,全称为立即调用的函数表

深入理解ajax系列第三篇

前面的话 我们接收到的响应主体类型可以是多种形式的,包括字符串String.ArrayBuffer对象.二进制Blob对象.JSON对象.javascirpt文件及表示XML文档的Document对象等.下面将针对不同的主体类型,进行相应的响应解码 属性 在介绍响应解码之前,要先了解XHR对象的属性.一般地,如果接受的数据是字符串,使用responseText即可,这也是最常用的用于接收数据的属性.但如果获取了其他类型的数据,使用responseText可能就不太合适了 [responseTex

深入理解ajax系列第三篇——头部信息

前面的话 每个HTTP请求和响应都会带有相应的头部信息,其中有的对开发人员有用.XHR对象提供了操作头部信息的方法.本文将详细介绍HTTP的头部信息 默认信息 默认情况下,在发送XHR请求的同时,还会发送下列头部信息 Accept: 浏览器能够处理的内容类型 Accept-Charset: 浏览器能够显示的字符集 Accept-Encoding: 浏览器能够处理的压缩编码 Accept-Language: 浏览器当前设置的语言 Connection: 浏览器与服务器之间连接的类型 Cookie:

深入理解javascript函数系列第三篇

前面的话 函数是javascript中特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本文是深入理解javascript函数系列第三篇--属性和方法 属性 [length属性] 函数系列第二篇中介绍过,arguments对象的length属性表示实参个数,而函数的length属性则表示形参个数 function add(x,y){ console.log(arguments.length)//3 console.log(

深入理解javascript作用域系列第三篇

前面的话 一般认为,javascript代码在执行时是由上到下一行一行执行的.但实际上这并不完全正确,主要是因为声明提升的存在.本文是深入理解javascript作用域系列第三篇--声明提升(hoisting) 变量声明提升 a = 2 ; var a; console.log( a ); 直觉上,会认为是undefined,因为var a声明在a = 2;之后,可能变量被重新赋值了,因为会被赋予默认值undefined.但是,真正的输出结果是2 console.log( a ) ; var a

深入理解javascript作用域系列第三篇——声明提升(hoisting)

× 目录 [1]变量 [2]函数 [3]优先 前面的话 一般认为,javascript代码在执行时是由上到下一行一行执行的.但实际上这并不完全正确,主要是因为声明提升的存在.本文是深入理解javascript作用域系列第三篇——声明提升(hoisting) 变量声明提升 a = 2 ; var a; console.log( a ); 直觉上,会认为是undefined,因为var a声明在a = 2;之后,可能变量被重新赋值了,因为会被赋予默认值undefined.但是,真正的输出结果是2 c

深入理解JavaScript系列(结局篇)(转载)

深入理解JavaScript系列(结局篇) 介绍 最近几个月忙得实在是不可开交,终于把<深入理解JavaScript系列>的最后两篇“补全”了,所谓的全是不准确的,因为很多内容都没有写呢,比如高性能.Ajax安全.DOM详解.JavaScript架构等等.但因为经历所限,加上大叔希望接下来写点其它东西,所以此篇文字就暂且当前完结篇的总结吧,以后有时间的话,可以继续加上一些未涉及的专题内容. 网络文章来源 本系列文章参考了大量的互联网网站,在此向各位网站拥有者.博主.提到的以及未提到的作者们说一

javascript面向对象系列第三篇——实现继承的3种形式

前面的话 学习如何创建对象是理解面向对象编程的第一步,第二步是理解继承.开宗明义,继承是指在原有对象的基础上,略作修改,得到一个新的对象.javascript主要包括类式继承.原型继承和拷贝继承这三种继承方式.本文是javascript面向对象系列第三篇——实现继承的3种形式 类式继承 大多数面向对象的编程语言都支持类和类继承的特性,而JS却不支持这些特性,只能通过其他方法定义并关联多个相似的对象,如new和instanceof.不过在后来的ES6中新增了一些元素,比如class关键字,但这并不