首页 > 解决方案 > 如何根据服务器响应启动计时器

问题描述

我想根据服务器响应启动倒数计时器。我首先为本地测试制作了一个计时器,在该测试中我通过了员工姓名、小时、分钟和秒。它工作正常。但现在我想将倒数计时器作为服务器数据启动。它将在一分钟内获取员工姓名和倒数计时器时间。但它没有正确拆分 json 对象。它显示 var 有未定义的数据。

API响应-[{"EmployeeName":"Abc","Hour":9,"Min":25},{"EmployeeName":"Xyz","Hour":11,"Min":41}]

Javascript

function GetMachine() {

var http = new XMLHttpRequest();
var url = 'php/StitchTimer.php';
http.open('GET', url, true);

http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
http.onreadystatechange = function() {//Call a function when the state changes.
if(http.readyState == 4 && http.status == 200) {
    var data = http.responseText;
    var jsonResponse = JSON.parse(data);
     for(var i=0;i<jsonResponse.length;i++){
    var index = jsonResponse[i];
    console.log(index);
    var empname = index["EmployeeName"];
    var hour = index["Hour"];
    var minute = index["Min"];


    addEmployee(empname,hour,minute);
    }
}
http.send();
}
}
function addEmployee(emp,hr,mi)
        { 
            var employee = new Employee(emp,hr,mi,00);
            employeeList.appendChild(employee.domObj);
            employee.startTimer();
        }
    class Employee
        {   
            constructor(name,hr,min,sec)
            {
                var self=this;

                this.timer;
                this.timeInSec;
                this.domObj=document.createElement("div");
                this.timeSpan=document.createElement("span");

                this.domObj.style.backgroundColor = '#4CA';
                this.domObj.style.border = 'none';
                this.domObj.style.height = '100px';
                this.domObj.style.width = '100px';
                this.domObj.style.color = 'white';
                this.domObj.style.padding = '20px';
                this.domObj.style.textAlign = 'center';
                this.domObj.style.textDecoration = 'none';
                this.domObj.style.display = 'inline-block';
                this.domObj.style.fontSize = '26px';
                this.domObj.style.borderRadius = '50%';
                this.domObj.style.margin = '20px';
                this.domObj.style.justifyContent = "center";

                this.timeInSec=hr*60*60+min*60+parseInt(sec);
                this.timeSpan.innerHTML=hr+":"+min+":"+sec;
                this.domObj.innerHTML=name+"<br>";
                this.domObj.appendChild(this.timeSpan);
                console.log("0:"+this.timeInSec);
            }               
            startTimer()
            {
                this.timer=setInterval(this.updateTime.bind(this),1000);
            }
            updateTime()
            {
                var hr,min,sec,temp;

                if (this.timeInSec<=0)
                {
                    clearInterval(this.timer);
                }
                else
                {
                    this.timeInSec--;
                    //console.log("1:"+this.timeInSec);
                    sec=this.timeInSec % 60;
                    temp=this.timeInSec-sec;
                    temp/=60;
                    //console.log("2:"+temp);
                    min=temp % 60;
                    temp-=min;
                    hr=temp/60;

                    this.timeSpan.innerHTML=hr+":"+min+":"+sec;
                }
            }
}

PHP 代码

<?php
    date_default_timezone_set('Asia/Kolkata');

    $con = mysqli_connect("localhost","username","pw","db");
    $currenttime = date("Y-m-d H:i");

    $sql = "SELECT * FROM `Stitch` WHERE `EndTime` > '$currenttime' ";
    $res = mysqli_query($con,$sql);
    $result = array();

    while($row = mysqli_fetch_array($res))
    {
        $end = $row['EndTime'];
        $end = strtotime($end);
        $current = strtotime($currenttime);
        $timer = $end-$current;
        $timer = $timer/60;

        $hour = floor($timer/60);
        $min = $timer-($hour*60);

        $result[]=array('EmployeeName' =>$row['WorkerName'],'Hour'=>$hour,'Min'=>$min);
    }

    echo json_encode($result);
    mysqli_close($con);

?>

标签: javascriptphpjquery

解决方案


我不确定您最初的问题是什么,但您可以通过多种方式简化解决方案。

1:使用 Fetch API

Fetch API在所有现代浏览器中都可用,并且有一个适用于 IE10 浏览器的polyfill。它为在浏览器中获取资源提供了一个更简洁的界面——无需处理 readyState 和响应代码。

fetch(url)
.then(function(response){
  // return the response as JSON
  return response.json();
})
.then(function(data){
  // use the JSON data here
})
.catch(function(err){
  console.log('Request failed', err);
});

fetch()将数据 URL 作为参数并返回一个Promise。如果fetch()动作成功完成,响应将被传递给then()链,否则我们将有一个错误需要处理。

2:利用 JSON

从服务器返回的数据被解析为 JSON。无需复制单个元素来构造新对象,因为您已经拥有此类对象的数组。

假设来自服务器的响应是:

[{"EmployeeName":"Abc","Hour":9,"Min":25},{"EmployeeName":"Xyz","Hour":11,"Min":41}]

然后将是一个包含该精确结构的数组对象,您可以使用该方法data迭代数组的元素。forEach()

data.forEach(function(item){
  // item is the current element being processed
  console.log(item.EmployeeName);
  // Output:
  // "Abc"
  // "Xyz"
});

data对象包含初始状态,没有什么可以阻止您对其进行更改以满足您的需求。请记住,如果您尝试访问不存在的值或属性,它将被分配一个类型为undefined.

3:定时器是有代价的

您的解决方案为数组中返回的每个单独元素声明了一个计时器。如果您需要显示 1000 个项目,那么就是声明了 1000 个计时器。或者,您可以实现一个计时器并让处理程序遍历您的元素集合,更新每个元素的时钟。

4:浏览器可以设置内容样式

这只是一个小问题。不要为每个动态创建的元素设置相同的样式属性,而是定义一个 CSS 规则或添加一个样式标记并将适当的 CSS 类添加到您的新 HTML 元素。有关更详细的示例,请参阅Element.classList

var divElement = document.createElement('div');
divElement.classList.add('div-class-name');

这是一个不需要Employee类的实现,并使用如上所述的单个计时器。使用 DOM 元素上的数据属性跟踪各个时钟的状态,但它也可以很容易地记录在原始data对象中。

要试用代码,请将dataUrl变量设置为数据源的正确 URL。

JavaScript:

(function(){
  var dataUrl = ''; // where the data comes from
  var containerId = 'timers-container'; // existing container element in the DOM
  var activeClocksSelector = '#timers-container .timer-str.active';
  var dataAttrSeconds = 'data-seconds';
  var countdownTimerId;

  // helper to zero pad time elements
  function getZeroPaddedValue(value) {
    return (value < 10) ? '0' + value : value; 
  }

  // returns a correctly formatted time string
  function getFormattedTimeString(secondsParam) {
    var secondsNum = parseInt(secondsParam, 10);
    var hours = Math.floor(secondsNum / 3600);
    var minutes = Math.floor((secondsNum - (hours * 3600)) / 60);
    var seconds = secondsNum - (hours * 3600) - (minutes * 60);
    return getZeroPaddedValue(hours) + ':' + getZeroPaddedValue(minutes) + 
            ':' + getZeroPaddedValue(seconds);
  }

  // convert time elements to a number of seconds
  function getCountdownSeconds(hours, minutes, seconds) {
    var hh = (typeof hours !== 'undefined') ? parseInt(hours, 10) * 3600 : 0;
    var mm = (typeof minutes !== 'undefined') ? parseInt(minutes, 10) * 60 : 0;
    var ss = (typeof seconds !== 'undefined') ? parseInt(seconds, 10) : 0;
    return hh + mm + ss;
  }

  // setInterval callback handler
  function updateCountdownClocks() {
    var element, i, seconds;
    // get the active countdown clock elements
    var activeClockElements = document.querySelectorAll(activeClocksSelector);
    var numActiveClocks = activeClockElements.length;
    if (numActiveClocks > 0) {
      // loop through the elements
      for (i=0; i < numActiveClocks; i++) {
        element = activeClockElements[i];
        seconds = 0; // use a sensible default
        // check that the 'data-seconds' attribute is present
        if (element.hasAttribute(dataAttrSeconds)) {
          // decrement the number of seconds
          seconds = parseInt(element.getAttribute(dataAttrSeconds), 10) - 1;
        }
        // update the 'data-seconds' attribute
        element.setAttribute(dataAttrSeconds, seconds);
        // update the UI
        element.textContent = getFormattedTimeString(seconds);
        // check if counter needs to remain active
        if (seconds < 1) {
          element.classList.remove('active');
        }
      }
    } else {
      // remove the timer because the active clocks collection is empty
      clearInterval(countdownTimerId);
    }
  }

  // creates the DOM structure
  function setApplicationState(data) {
    // Are there items in the array?
    if (0 < data.length) {
      // get a handle on the DOM container element
      var container = document.getElementById(containerId);

      // use DocumentFragment object for efficiency
      var fragment = document.createDocumentFragment();

        // iterate through the array of data items
        data.forEach(function(item){
        // determine the number of seconds in the countdown timer
        var seconds = getCountdownSeconds(item.Hour, item.Min);
        // create HTML elements
        var outerDiv = document.createElement('div');
        var innerDiv = document.createElement('div');

        // populate outer div content
        outerDiv.classList.add('timer-block');
        outerDiv.textContent = item.EmployeeName;

        // populate inner div content
        innerDiv.classList.add('timer-str');
        // add a class to indicate the item is active
        if (0 < seconds) {
          innerDiv.classList.add('active');
        }
        // initialise the 'data-seconds' attribute
        innerDiv.setAttribute(dataAttrSeconds, seconds);
        innerDiv.textContent = getFormattedTimeString(seconds);
        // append the HTML elements
        outerDiv.appendChild(innerDiv);
        fragment.appendChild(outerDiv);
      });

      // add the DocumentFragment to the DOM
      container.appendChild(fragment);
    }
    // must return a value
    return data;
  }

  // start the countdown clocks
  function startTheTimer(data) {
    // keep track of the interval ID
    countdownTimerId = setInterval(updateCountdownClocks, 1000);
    // promise chain must return a value
    return data;
  }

  // using the Fetch API to retrieve the initial state
  var state = fetch(dataUrl)
    .then(function(response){
      // return the parsed JSON content
      return response.json();
    })
    .then(setApplicationState)
    .then(startTheTimer)
    .catch(function(err){
      console.log('Request failed', err);
    });
})();

CSS:

#timers-container .timer-block {
  background-color: #4CA;
  border: none;
  border-radius: 50%;
  color: white;
  display: inline-block;
  font-size: 26px;
  height: 100px;
  justify-content: center;
  margin: 20px;
  padding: 20px;
  text-align: center;
  text-decoration: none;
  width: 100px;
}

HTML:

<div id="timers-container"></div>

推荐阅读