No.25

做一个计时器的总结

  • 使用上方的HTML结构(可以根据需要自行微调)为基础编写JavaScript代码
  • 当变更任何一个select选择时,更新 result-wrapper 的内容
  • 当所选时间早于现在时间时,文案为 现在距离 "所选时间" 已经过去 xxxx
  • 当所选时间晚于现在时间时,文案为 现在距离 "所选时间" 还有 xxxx
  • 注意当前时间经过所选时间时候的文案变化
  • 注意选择不同月份的时候,日期的可选范围不一样,比如1月可以选31天,11月只有30天,注意闰年
  • 同样,需要注意,通过优雅的函数封装,使得代码更加可读且可维护


    计时器

一 思路

  • 先设置六个选择框的值,分别用循环函数insertNode(start,end,parentNode)插入节点注意月份值有30、31和是否闰年2月29、28的变化
  • 其次为了获得结果是天时分秒,所以用当前时间-选择框的时间的秒数,可以用得到的秒数得出天数(86400s)创建pastOrFutureTime()函数
  • 每次点击年和月的时候日期都会发生变化,所以为两者创建一个改变时间
  • 把结果输出

二 总结

  1. 把所有的代码放在一个(function init(){ ....... })();的匿名自执行的函数中,可以不会生成全局变量,并且局部变量使用完之后所占的空间就会被回收了,多多把代码放进函数
  2. 迅雷的插件会造成Cannot read property ‘nodeName’ of null解决办法删除即可
  3. 计数器setinterval()如果要在一个函数中自动调用的话,需要在函数之外最少执行一次才会出发函数内部的计时器。
  4. 也可以在外面创建一个函数用计时器执行它
function update(){
    result.innerHTML=pastOrFutureTime();
}
setInterval(update,1000);

三 具体分解如下

insertNode(start,end,parentNode)为了插入不同的值,因为每个选择框插入的值有差别,所以传入start和end控制长度,parentNode是控制父节点的类型。

                var yearNode=document.querySelector("#year-select");
                var monthNode=document.querySelector("#month-select");
                var dayNode=document.querySelector("#day-select");
                var hourNode=document.querySelector("#hour-select");
                var miniteNode=document.querySelector("#minite-select");
                var secondNode=document.querySelector("#second-select");
                var result=document.querySelector("#result-wrapper");
                function insertNode(start,end,parentNode)//父节点,开始和结束值
                {
                    for(var i=start;i<=end;i++)
                    {
                        var node=document.createElement("option");
                        node.innerHTML = i;
                        parentNode.appendChild(node);
                    }
                }
                        insertNode(1997, 2032, yearNode);
                        insertNode(1, 12, monthNode);
                        insertNode(0, 23, hourNode);
                        insertNode(0, 59, miniteNode);
                        insertNode(0, 59, secondNode);
                        insertNode(1,setMonthDays(), dayNode);

1年月和时分秒都是固定值,只有月份里面的天数是不固定的,有1、3、5、7、8、10、12每月天数为31天,4、6、9、11月的天数为30,闰年的2月为29天,非闰年则为28天。所以用一个setMonthDays()swith语句可以方便的创建2月之外的天数,再用一个判断是否为闰年的函数isLeapYear(year),来为2月赋值。

function isLeapYear(year) {
                            return (year % 100 != 0 && year % 4 == 0) || (year % 400 == 0);//0 is false,大于0 is TRUE
                        }
                        function setMonthDays() {
                            var year = yearNode.value,
                            month = monthNode.value;
                            var days=0;
                            switch(month) {
                                case "1":
                                case "3":
                                case "5":
                                case "7":
                                case "8":
                                case "10":
                                case "12": days=31;
                                break;
                                case "2":if(isLeapYear(year)) {
                                    days=29;
                                }
                                else{
                                    days=28;
                                }
                                break;
                                case "4":
                                case "6":
                                case "9":
                                case "11": days=30;
                                break;
                            }
                            return days;
                        }

为年月创建点击事件来触发每月日期天数的变化,并且改变一次之前需要把原来的插入的节点给清空,设置值为空

window.onchange=function(e){
                        if(e.target==monthNode){
                            dayNode.innerHTML="";
                            insertNode(1,setMonthDays(), dayNode);
                        }
                        if(e.target==yearNode){
                            dayNode.innerHTML="";
                            insertNode(1,setMonthDays(), dayNode);
                        }
                    }

计算距离过去和未来的时间,需要用毫秒数来计算时间,首先取得选择框的值,和当前时间,创建选择框日期直接用new Date(year,month,....)就行,如果用UTC否则返回的毫秒数有误差。
如果现在时间毫秒数大于选择时间,则用now - select,否则用select - now,在这计算天数seconds / 86400需要取Math.floor()上取约数,否则会造成误差

var str="";
                    function pastOrFutureTime(){
                        var startNow = Date.now(),//现在时间距离1970年的秒数
                        selectSeconds,//选择的时间距离1970年的秒数
                        intervalSeconds,//现在时间减去选择的时间的间隔秒数
                        yearSelect=Number(yearNode.value),
                        monthSelect=Number(monthNode.value)-1,
                        daySelect=Number(dayNode.value),
                        hourSelect=Number(hourNode.value),
                        minitesSelect=Number(miniteNode.value),
                        secondsSelect=Number(secondNode.value),
                        diffday,
                        diffhour,
                        diffminite,
                        diffsecond,
                        flag;//命名区别符号在前面,相同者在后面比如
                        selectSeconds=new Date(yearSelect, monthSelect, daySelect, hourSelect, minitesSelect, secondsSelect);
                        
                        if(selectSeconds < startNow)
                        {
                            intervalSeconds = (startNow - selectSeconds) / 1000;
                            flag=1;
                        }
                        if(selectSeconds>startNow){
                            intervalSeconds = (selectSeconds - startNow) / 1000;
                            flag=2;
                        }
                        diffday = Math.floor(intervalSeconds / 86400);
                        intervalSeconds = intervalSeconds % 86400;
                        diffhour = Math.floor(intervalSeconds / 3600);
                        intervalSeconds =  intervalSeconds % 3600;
                        diffminite =Math.floor(intervalSeconds / 60);
                        intervalSeconds = intervalSeconds % 60;
                        diffsecond =Math.floor(intervalSeconds);
                        if(flag==1){
                            str="现在距离 " + yearSelect +"年" + (monthSelect+1) + "月" + daySelect + "日" +weeks[selectSeconds.getDay()]+ " 已经过去" + diffday + "天" + diffhour +"小时" + diffminite + "分" +diffsecond + "秒";
                        }
                        if(flag==2){
                            str="现在距离 " + yearSelect +"年" + (monthSelect+1) + "月" + daySelect + "日" +weeks[selectSeconds.getDay()]+ " 还有" + diffday + "天" + diffhour +"小时" + diffminite + "分" +diffsecond + "秒";
                        }
                        result.innerHTML=str;
                        setInterval(pastOrFutureTime,1000);
                    }
                    pastOrFutureTime();
                    result.innerHTML=str;

下面为全部代码


<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <select id="year-select">
        
        </select>
        
        <select id="month-select">
            
        </select>
        
        <select id="day-select">
            
        </select>
        
        <select id="hour-select">
            
        </select>
        
        <select id="minite-select">
            
        </select>
        
        <select id="second-select">
            
        </select>
        
        <p id="result-wrapper">现在距离 2001年1月1日星期X HH:MM:SS 还有 X 天 X 小时 X 分 X 秒</p>
        <script>
            (function init(){
                var weeks=["星期日","星期一","星期二","星期三","星期四","星期五","星期六"];
                var yearNode=document.querySelector("#year-select");
                var monthNode=document.querySelector("#month-select");
                var dayNode=document.querySelector("#day-select");
                var hourNode=document.querySelector("#hour-select");
                var miniteNode=document.querySelector("#minite-select");
                var secondNode=document.querySelector("#second-select");
                var result=document.querySelector("#result-wrapper");
                function insertNode(start,end,parentNode)//父节点,开始和结束值
                {
                    for(var i=start;i<=end;i++)
                    {
                        var node=document.createElement("option");
                        node.innerHTML = i;
                        parentNode.appendChild(node);
                    }
                }
                        insertNode(1997, 2032, yearNode);
                        insertNode(1, 12, monthNode);
                        insertNode(0, 23, hourNode);
                        insertNode(0, 59, miniteNode);
                        insertNode(0, 59, secondNode);
                        insertNode(1,setMonthDays(), dayNode);
                        function isLeapYear(year) {
                            return (year % 100 != 0 && year % 4 == 0) || (year % 400 == 0);//0 is false,大于0 is TRUE
                        }
                        function setMonthDays() {
                            var year = yearNode.value,
                            month = monthNode.value;
                            var days=0;
                            switch(month) {
                                case "1":
                                case "3":
                                case "5":
                                case "7":
                                case "8":
                                case "10":
                                case "12": days=31;
                                break;
                                case "2":if(isLeapYear(year)) {
                                    days=29;
                                }
                                else{
                                    days=28;
                                }
                                break;
                                case "4":
                                case "6":
                                case "9":
                                case "11": days=30;
                                break;
                            }
                            return days;
                        }
                    /*
                        Uncaught TypeError: Cannot read property 'nodeName' of null at HTMLDocument.onMouseClick (content.js:170)
                        以上为迅雷插件所为,卸载掉迅雷的浏览器插件即可消失
                     */
                    /*利用事件委托,减少DOM节点操作*/
                    window.onchange=function(e){
                        if(e.target==monthNode){
                            dayNode.innerHTML="";
                            insertNode(1,setMonthDays(), dayNode);
                        }
                        if(e.target==yearNode){
                            dayNode.innerHTML="";
                            insertNode(1,setMonthDays(), dayNode);
                        }
                    }
                    var str="";
                    function pastOrFutureTime(){
                        var startNow = Date.now(),//现在时间距离1970年的秒数
                        selectSeconds,//选择的时间距离1970年的秒数
                        intervalSeconds,//现在时间减去选择的时间的间隔秒数
                        yearSelect=Number(yearNode.value),
                        monthSelect=Number(monthNode.value)-1,
                        daySelect=Number(dayNode.value),
                        hourSelect=Number(hourNode.value),
                        minitesSelect=Number(miniteNode.value),
                        secondsSelect=Number(secondNode.value),
                        diffday,
                        diffhour,
                        diffminite,
                        diffsecond,
                        flag;//命名区别符号在前面,相同者在后面比如
                        selectSeconds=new Date(yearSelect, monthSelect, daySelect, hourSelect, minitesSelect, secondsSelect);
                        
                        if(selectSeconds < startNow)
                        {
                            intervalSeconds = (startNow - selectSeconds) / 1000;
                            flag=1;
                        }
                        if(selectSeconds>startNow){
                            intervalSeconds = (selectSeconds - startNow) / 1000;
                            flag=2;
                        }
                        diffday = Math.floor(intervalSeconds / 86400);
                        intervalSeconds = intervalSeconds % 86400;
                        diffhour = Math.floor(intervalSeconds / 3600);
                        intervalSeconds =  intervalSeconds % 3600;
                        diffminite =Math.floor(intervalSeconds / 60);
                        intervalSeconds = intervalSeconds % 60;
                        diffsecond =Math.floor(intervalSeconds);
                        if(flag==1){
                            str="现在距离 " + yearSelect +"年" + (monthSelect+1) + "月" + daySelect + "日" +weeks[selectSeconds.getDay()]+ " 已经过去" + diffday + "天" + diffhour +"小时" + diffminite + "分" +diffsecond + "秒";
                        }
                        if(flag==2){
                            str="现在距离 " + yearSelect +"年" + (monthSelect+1) + "月" + daySelect + "日" +weeks[selectSeconds.getDay()]+ " 还有" + diffday + "天" + diffhour +"小时" + diffminite + "分" +diffsecond + "秒";
                        }
                        result.innerHTML=str;
                        setInterval(pastOrFutureTime,1000);
                    }
                    pastOrFutureTime();
                    result.innerHTML=str;
//                  function update(){
//                      result.innerHTML=pastOrFutureTime();
//                  }
//                  
                })();
        </script>
    </body>
</html>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容