javascript - 如何根据服务器响应启动计时器
问题描述
我想根据服务器响应启动倒数计时器。我首先为本地测试制作了一个计时器,在该测试中我通过了员工姓名、小时、分钟和秒。它工作正常。但现在我想将倒数计时器作为服务器数据启动。它将在一分钟内获取员工姓名和倒数计时器时间。但它没有正确拆分 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);
?>
解决方案
我不确定您最初的问题是什么,但您可以通过多种方式简化解决方案。
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>
推荐阅读
- google-signin - 使用“谷歌登录令牌”到另一个服务
- docker - docker 镜像的默认命令
- php - PHP - 按我想要的类别对数组进行排序
- android - runBlocking 不等待一切
- python - 如何在 python 的 mac os 上解压缩 .app.zip 文件?
- python - Pyspark UDF 收到错误“java.lang.NullPointerException”
- python - 使用 matplotlib 3D scatter,第 3 维被忽略
- java - 使用@TestPropertySource 时属性始终为空@ConfigurationProperties
- mongodb - 匹配填充不适用于猫鼬
- powerbi - Power BI 为每个用户导出 PDF 报告