【问题标题】:Multiple countdown timers on one page一页上有多个倒计时
【发布时间】:2014-05-12 20:39:30
【问题描述】:

目前正在处理一个需要在一个页面上显示两个计时器的项目。计时器需要有一个开始按钮,并且两者都有不同的计时(即 timer1 持续 10 秒,timer2 持续 20 秒)。这是我正在使用的脚本,但我不知道如何复制计时器并让每个计时器独立工作。

有没有人可以轻松地将此脚本更改为可运行的两个计时器?

<html>
<head>
<script language="JavaScript" type="text/javascript">
    var interval;
    var minutes = 0;
    var seconds = 10;

    function countdown(element) {
        interval = setInterval(function(timer) {
            var el = document.getElementById(element);
            if(seconds == 0) {
                if(minutes == 0) {
                    (el.innerHTML = "STOP!");     

                    clearInterval(interval);
                    return;
                } else {
                    minutes--;
                    seconds = 60;
                }
            }
            if(minutes > 0) {
                var minute_text = minutes + (minutes > 1 ? ' minutes' : ' minute');
            } else {
                var minute_text = '';
            }
            var second_text = seconds > 1 ? '' : '';
            el.innerHTML = minute_text + ' ' + seconds + ' ' + second_text + '';
            seconds--;
        }, 1000);
    }
var start = document.getElementById('start');

start.onclick = function(timer) {
    if (!interval) {
        countdown('countdown');
    }
}

</script>
</head>

<body>
<div id='countdown'></div>
<input type="button" onclick="countdown('countdown');this.disabled = true;" value="Start" />
</body>
</html>

【问题讨论】:

    标签: javascript timer countdown


    【解决方案1】:

    您正在做的事情很少会阻止您扩展代码。如果你想要一个可重复使用的计时器,你不能硬设置它将使用的变量。所以首先要做的是去掉顶部的三个变量,并在函数范围内重新创建它们。

    这样,每次调用函数时,都会为其执行创建一组新变量。

    分钟和秒可能最好作为参数传递,间隔应该在函数范围内定义。

    其次,您要在内联和脚本内设置点击处理程序。摆脱其中一个(最好摆脱内联版本)。

    然后,您有一个计时器变量作为单击处理程序和 setInterval 的参数,但从未使用过。该变量将设置为事件处理程序上的单击事件(同样,未使用),并且在 setInterval 上未定义。所以他们真的不应该在那里。

    您可能想知道的一个性能问题是您每秒钟都在对计数器进行 DOM 查找。您应该在每个函数调用开始时获取一次并缓存它。

    那时,你的函数看起来或多或少像这样

    function countdown(element, minutes, seconds) {
        // Fetch the display element
        var el = document.getElementById(element);
    
        // Set the timer
        var interval = setInterval(function() {
            if(seconds == 0) {
                if(minutes == 0) {
                    (el.innerHTML = "STOP!");     
    
                    clearInterval(interval);
                    return;
                } else {
                    minutes--;
                    seconds = 60;
                }
            }
    
            if(minutes > 0) {
                var minute_text = minutes + (minutes > 1 ? ' minutes' : ' minute');
            } else {
                var minute_text = '';
            }
    
            var second_text = seconds > 1 ? '' : '';
            el.innerHTML = minute_text + ' ' + seconds + ' ' + second_text + '';
            seconds--;
        }, 1000);
    }
    

    你的设置或多或少像这样

    //Start as many timers as you want
    
    var start1 = document.getElementById('timer1');
    var start2 = document.getElementById('timer2');
    
    start1.onclick = function() {
        countdown('countdown1', 0, 15);
    }
    
    start2.onclick = function() {
        countdown('countdown2', 0, 10);
    }
    

    当然,你需要额外的按钮和计数器

    <div id='countdown1'></div>
    <div id='countdown2'></div>
    <input id="timer1" type="button" value="Start timer 1" />
    <input id="timer2" type="button" value="Start timer 2" />
    

    工作示例:http://codepen.io/anon/pen/Jmpcq/?editors=101

    -- 注意:对于精确计时器,setInterval() 可能不是一个好的选择,因为不能保证精确的时间间隔,并且它跟踪的时间可能会延迟一段时间。对于精确时间至关重要的应用程序,还有其他方法(例如https://sitepoint.com/creating-accurate-timers-in-javascript & https://html5rocks.com/en/tutorials/webperformance/usertimin),感谢@KaiKarver 在 cmets 中指出。

    【讨论】:

    • 很高兴给出一个工作示例。但是取决于setInterval() 的时间不是很准确。更好地使用例如Date.now() 了解时间信息,请参阅例如sitepoint.com/creating-accurate-timers-in-javascript 如果你想要更高的精度,试试performance.now() html5rocks.com/en/tutorials/webperformance/usertiming
    • 干杯@KaiCarver,您对准确性的看法是正确的,感谢您的链接,但是,问题是关于如何拥有多个计时器而不是如何使它们更准确,所以我认为没有意义一个比它必须的更复杂的答案。
    • 好吧,您确实提到了一个(相当无关紧要的)性能问题,尽管问题不是关于提高性能...我的意思是人们(像我一样!)可能会遇到这篇文章,寻找一种简单的方法在一个页面上实现多个计时器,并且可能不知道实现的计时器可能非常不准确。因此,在您原本有用的答案中稍微提及这一事实可能是一项公共服务。
    • 这是一个公平的观点,我已经编辑了答案以添加注释。
    • 感谢@guioconnor!顺便说一句,几天前我实际上分叉了你的示例笔,用于无限多个计数器计数......它仍然有不准确的计时器......因为我很懒,当时没关系,哈哈。但我可能有一天会修复它codepen.io/kaicarver/pen/pyaKVR?Joe,Jack,Jill
    【解决方案2】:

    很长但有效

    let d = document,
        id = 'getElementById',
        time = {
    //Multiple Timers
    //[current time, time setting, (pause/running), HTML section#timer]
          timer1: ['0:10', '0:10', 0, d[id]('timer1')],
          timer2: ['2:30', '2:30', 0, d[id]('timer2')],
          timer3: ['5:00', '5:00', 0, d[id]('timer3')],
    
    
    //Manage Timer Functions
          reset: function(t) {time[t][0] = time[t][1];},
          pause: function(t) {time[t][2] = 0;time.state(t,'pause');time.button(t,'resume');},
          resume: function(t) {time[t][2] = 1;time.state(t,'running');time.button(t,'pause');},
          set: function(t,s) {time[t][0] = s; time[t][1] = s;},
          state: function(t,s) {time[t][3].setAttribute('state',s);},
          button: function(t,s) {time[t][3].querySelector('div').innerHTML = s;},
          cancel: function(t) {time[t][2] = 0;time.reset(t);time.state(t,'');time.button(t,'start');time.setTimer(t);},
          start: function(t) {time.reset(t);time[t][2] = 1;time.state(t,'running');time.button(t,'pause');},
          getTimers: function() {return Object.keys(time).filter(function (n) {return n.indexOf("ti")==0;});},
          setTimer: function(t) {time[t][3].querySelector('span').innerHTML = time[t][0]},
          setTimers: function(x) {
            let times = time.getTimers();
            for (var i=0,t;i<times.length;i++) {t=times[i];
                  if(time[t][2]||x){time[t][3].querySelector('span').innerHTML = time[t][0]}
            }
      },
    };
    
    //handle seconds passed
    function convertSeconds(s=0) {return new Date(s*1000).toISOString().substr(11,8).replace(/^(00:0(?=[1-9])|00:|0)/gm, '')}
    function toSeconds(t) {t=t.split(':').reverse();return (t[2]*3600||0)+(t[1]*60||0)+t[0]*1||0;}
    
    //set HTML times onLoad
    time.setTimers(1)
    
    
    function runTimer(times){times = time.getTimers();time.setTimers();
        function run(t,s,l){if(t&&t[2]){s=toSeconds(t[0]);t[0]=s?convertSeconds(s-1):'00:00'&&(time.cancel(l));}}
        for (var i=0,t;i<times.length;i++) {run(time[times[i]],'',times[i])}
    }
    
    //run timer every second reguardless of whether timer is paused or running
    setInterval(runTimer, 1000)
    body {
      background: #e6e9f0;
      user-select: none;
      font-family: "SF Pro Display", Helvetica Neue, Arial, Helvetica, Geneva, sans-serif;
      font-size: 14px;
    }
    div, span {display: inline-block;}
    span {min-width: 60px;}
    #time > section {
      padding: 10px 20px;
      background: white;
      margin: 10px;
      border-radius: 4px;
      transition: .15s ease-in-out 0s;
      text-transform: capitalize;
    }
    #time > section:hover {box-shadow: 0px 0px 0px 2px #A8D1FD;}
    #time > section > div{text-shadow: 0 1px 1px rgba(0,0,0,0.3);transition: .1s ease-in-out 0s;}
    #time > section > div:nth-of-type(2){background: #cfd3dd;opacity: 1;}
    #time > section[state=""] > div:nth-of-type(2) {opacity: 0;}
    #time > section > div{
      background: #368ad2;
      color: white;
      padding: 6px 10px;
      margin: 0 5px;
      min-width: 50px;
      text-align: center;
      border-radius: 4px;
    }
    <section id="time">
      <section id="timer1" state="">
        <span>0:00</span>
        <div onClick="time[this.innerHTML]('timer1')">start</div>
        <div onClick="time.cancel('timer1')">cancel</div>
      </section>
      <section id="timer2" state="">
        <span>0:00</span>
        <div onClick="time[this.innerHTML]('timer2')">start</div>
        <div onClick="time.cancel('timer2')">cancel</div>
      </section>
      <section id="timer3" state="">
        <span>0:00</span>
        <div onClick="time[this.innerHTML]('timer3')">start</div>
        <div onClick="time.cancel('timer3')">cancel</div>
      </section>
    </section>

    【讨论】:

      【解决方案3】:
      var interval;
      
      var countdown1 = {
          minutes:0,
          seconds: 10
      };
      
      var countdown2 = {
          minutes:0,
          seconds: 2
      }
      
      function countdown(element) {
          alert(element);
          var cd;
          element === 'countdown1' ? cd = countdown1 : cd = countdown2;
          interval = setInterval(function(timer) {
              var el = document.getElementById(element);
              if(cd.seconds == 0) {
                  if(cd.minutes == 0) {
                      (el.innerHTML = "STOP!");     
      
                      clearInterval(interval);
                      return;
                  } else {
                      cd.minutes--;
                      cd.seconds = 60;
                  }
              }
              if(cd.minutes > 0) {
                  var minute_text = cd.minutes + (cd.minutes > 1 ? ' minutes' : ' minute');
              } else {
                  var minute_text = '';
              }
              var second_text = seconds > 1 ? '' : '';
              el.innerHTML = minute_text + ' ' + cd.seconds + ' ' + second_text + '';
              cd.seconds--;
          }, 1000);
      }
      var start = document.getElementById('start');
      
      
       <div id='countdown'></div>
       <input type="button" onclick="countdown('countdown1');this.disabled = true;" value="Start" />
       <div id="countdown1"></div>
      
       <input type="button" onclick="countdown('countdown2');this.disabled = true;" value="Start" />
       <div id="countdown2"></div>
      

      小提琴:http://jsfiddle.net/dn3hJ/

      【讨论】:

      • 最好在顶部有一点解释,而不仅仅是原始代码。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-18
      • 2020-02-06
      • 1970-01-01
      • 1970-01-01
      • 2011-07-15
      相关资源
      最近更新 更多