【问题标题】:Trying to Create Countdown Timer for an array of Times尝试为时间数组创建倒数计时器
【发布时间】:2018-11-05 06:03:58
【问题描述】:

我正在尝试为自己打造一个小锻炼工具。在 Python 中,我正在构建一个随机的时间数组,每个时间都链接到一个随机的练习数组。在前端(在我的 html 模板中),我在侧面的类菜单中列出了所有这些。然后,我使用我的 javascript 通过 document.getElementsByClassName("exercises") 或 document.getElementsByClassName("times") 获取整个练习和时间数组。

我有一个开始按钮,点击后将开始我的锻炼。我希望它:对于 document.getElementsByClassName 中的每个元素:运行倒数计时器直到时间到期,在主屏幕上显示倒数计时器和锻炼。

function myfunction() {
  var times = document.getElementsByClassName('time');
  // console.log(times.item(0).innerHTML);
  var exercises = document.getElementsByClassName('exercise');
  var display = document.getElementById('currentexercise');
  for (var i = 0; i < times.length; i++) {

      var current = parseInt(times.item(i).innerHTML);
      var timeinterval = current;
      for (var j = 1; j <= timeinterval; j++) {
        
        runclock(current, i, exercises.item(i).innerHTML, display);
        current = current - 1;


      }


  }

 

  function runclock(current, i, exercise, display) {


    var x = setTimeout(function() {
      console.log(current);
      var now = new Date();
      var endoftime = new Date();
      endoftime.setSeconds(now.getSeconds() + parseInt(current));
      var distance = endoftime - now;
      var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
      var seconds = Math.floor((distance % (1000 * 60)) / 1000);
      console.log('hit');
      document.getElementById('mytimer').innerHTML = minutes + "m " + seconds + "s ";
      display.innerHTML = exercise;
      
    }, 1000);

  }
}
{% extends "base.html" %}

{% load static %}

{% block content %}
<div class = "row">
  <div class = "col-sm-3">
    {% if workout %}
      <ul class="list-group">
        {% for exercise in workout %}
          <li class="list-group-item exercises">{{ exercise.0 }}, {{ exercise.1 }}</li>
          <li class = "hidden time">{{ exercise.1 }}</li>
          <li class = "hidden exercise">{{ exercise.0 }}</li>
        {% endfor %}
      </ul>
    {% endif %}
  </div>
  <div class = "col-sm-9">
    {% if form %}
      <h1> Spences Workout Form</h1>
      <form action="/" method="post">
          {% csrf_token %}
          {{ form.as_p }}
          <input type="submit" value="Submit">
      </form>
    {% else %}
      <h1>Spences Workout Tool</h1>
      <h3>Rounds: {{ rounds }}</h3>
      <button id = "startbutton" onclick = "myfunction()">Start</button>
    {% endif %}

    <div id = "mytimer"></div>
    <div id = "currentexercise"></div>



  </div>
</div>


{% endblock %}

这是非常快速地通过每个命令,但我希望它像常规时钟计时器一样工作。我很难理解如何正确使用 setTimeout/setInterval。请让我知道如何在我的第二个 forloop 中基本上每秒只运行一次“j”。

谢谢!

【问题讨论】:

  • 我不熟悉 Python。 {{ exercise.1 }} 是做什么的?不应该是{{ exercise.time }}吗?我想exercise.0 是练习的名称,exercise.1 是练习的时间。时间格式是什么?
  • @DominiqueFortin 是对的。这是 Django/Jinja 语法,是后端相关的东西。请发布一个真实的示例(浏览器看到的),以便我们更轻松地调试它。

标签: javascript html


【解决方案1】:

这是我的建议:

function attr(o, attrName) {
  var stop, value;
  Array.prototype.forEach.call(o.attributes, function(e){
    if (stop) return;
    if (e.nodeName === attrName) {
      value = e.nodeValue;
      stop = 1;
    }
  });
  return value;
}

function init() {
  var exercises = document.getElementsByClassName('exercises');
  Array.prototype.forEach.call(exercises, function(e){
    var dataJSON = attr(e,'data');
    var data = JSON.parse(dataJSON);
    e.innerHTML = data.name+", "+Math.floor(data.time/1000);
  });
  exercises[0].onclick();
}
init();

function seeExerciseTime (o) {
  var currentexercise = document.getElementsByClassName('currentexercise');
  if (currentexercise.length && currentexercise.length > 0) {
    currentexercise[0].classList.remove('currentexercise');
  }
  var dataJSON = attr(o,'data');
  var data = JSON.parse(dataJSON);
  o.classList.add('currentexercise');
  document.getElementById('currentexercise').innerHTML = data.name;
}

var startoftime = 0;
function myfunction() {
  startoftime = (new Date()).getTime();

  setTimeout(tick, 1000);
}

function tick() {
  var currentexercise = document.getElementsByClassName('currentexercise');
  if (currentexercise.length && currentexercise.length > 0) {
    var dataJSON = attr(currentexercise[0],'data');
    var data = JSON.parse(dataJSON);
    var now = (new Date()).getTime();
    var distance = data.time - (now - startoftime);
    if (distance < 0) distance = 0;
    var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
    var seconds = Math.floor((distance % (1000 * 60)) / 1000);
    document.getElementById('mytimer').innerHTML = minutes +"m "+ seconds +"s ";
  }

  setTimeout(tick, 1000);
}
<div class = "row">
  <div class = "col-sm-3">
  Click on exercise to see the time remaining for the exercise.
      <ul class="list-group">
        <!-- {% for exercise in workout %} -->
          <li class="list-group-item exercises" data="{&quot;name&quot;:&quot;Alpha&quot;,&quot;time&quot;:60000}" onclick="seeExerciseTime(this)"></li>
          <li class="list-group-item exercises" data="{&quot;name&quot;:&quot;Beta&quot;,&quot;time&quot;:605345}" onclick="seeExerciseTime(this)"></li>
          <li class="list-group-item exercises" data="{&quot;name&quot;:&quot;Gamma&quot;,&quot;time&quot;:902323}" onclick="seeExerciseTime(this)"></li>
        <!-- {% endfor %} -->
      </ul>
  </div>
    <div id = "mytimer"></div>
    <div id = "currentexercise"></div>

  <div class = "col-sm-9">
    <!-- {% if form %}
      <h1> Spences Workout Form</h1>
      <form action="/" method="post">
          {% csrf_token %}
          {{ form.as_p }}
          <input type="submit" value="Submit">
      </form>
    {% else %} -->
      <h3>Spences Workout Tool</h1>
      <h4>Rounds: <!-- {{ rounds }} -->3</h3>
      <button id = "startbutton" onclick = "myfunction()">Start</button>
    <!-- {% endif %} -->

  </div>
</div>

我已经移动了一些东西,以便我们可以更好地看到时间。

【讨论】:

    【解决方案2】:

    setTimeout是一段时间后异步调用另一个函数的函数。你需要编程来照顾它。例如,如果你想做一个典型的sleep(1000)操作,你应该知道你需要告诉一秒钟后要执行什么函数。

    function myfunction(current=1) {
      var times = document.getElementsByClassName('time');
      // console.log(times.item(0).innerHTML);
      var exercises = document.getElementsByClassName('exercise');
      var display = document.getElementById('currentexercise');
      for (var i = 0; i < times.length; i++) {
    
          var end = parseInt(times.item(i).innerHTML);
          if(current <= end) {
            runclock(current, i, exercises.item(i).innerHTML, display);
          }
      }
    
      setTimeout(function() { myfunction(current+1) }, 1000);
    
      function runclock(current, i, exercise, display) {
          console.log(current);
          var now = new Date();
          var endoftime = new Date();
          endoftime.setSeconds(now.getSeconds() + parseInt(current));
          var distance = endoftime - now;
          var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
          var seconds = Math.floor((distance % (1000 * 60)) / 1000);
          console.log('hit');
          document.getElementById('mytimer').innerHTML = minutes + "m " + seconds + "s ";
          display.innerHTML = exercise;
      }
    }
    

    您可以在此处增强一些优化和设计模式,但计时器的问题应该通过此解决(或类似的东西,因为如果没有工作示例,我无法知道完整的 HTML 页面如何)。

    【讨论】:

    • 此方法不会显示正确的剩余时间。您不能依赖 setTimout 以完全预期的延迟调用该函数。另外,在这个版本中,runclock 只会被调用一次。
    • "您不能依赖 setTimeout 以完全预期的延迟调用函数" 为什么不呢?如果我希望它在 1000 毫秒内执行,我应该期待什么?
    • Also, in this version runclock will only be called once:每次调用 myfunction 时,每个项目都会调用一次,恰好是每个项目的 times.item(i).innerHTML 次。
    • 因为 javascript 是单线程的(web worker 除外),这意味着如果任何其他需要时间的 javascript 代码将在以后推迟回调。
    • 那你就不能改变DOM了。
    猜你喜欢
    • 2019-07-10
    • 2015-11-13
    • 2010-10-01
    • 2022-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多