在循环内多次执行 javascript 倒计时脚本
Executing javascript countdown script multiple times inside a loop
我正在使用 Symfony,我目前正在尝试显示数据库中的这些元素,但这里有一个转折点,因为这些元素中的每一个都有持续时间,我必须显示该持续时间的倒计时.
我已经实现了倒计时脚本(尽管它仍然存在一些问题)但它只执行第一个值,而其他行中的字段保持为空。
我现在解释一下代码:我有很多停车场,每个停车场都有很多车(voitures):我的页面显示了停车场,与它们相关的汽车以及每辆车的编号和时间的倒计时那辆车是允许的(时间在数据库的一列中注册)。
我还在我的脚本中使用 cookie 来节省时间,所以我不知道如何为多个值执行此操作。
这是我所做的照片:
这是我的代码(对不起,它很乱):
{% extends 'Agent/Baseagent.html.twig' %}
{% block title %}Parking index{% endblock %}
{% block body %}
{% for parking in user.parkings %}
<h2>Parking</h2>
{{ parking.libelle }}
<h2>voitures</h2>
<table id="file_export" class="table table-striped table-bordered">
<thead>
<tbody>
{% for voitures in parking.voitures %}
<tr>
<td>
{{ voitures.matricule }}
</td>
<td>
<div id="timer" class="js-user-rating" data-is-test="{{ voitures.time}}"></div>
<td class="center"><span id="demo"></span></td>
<script>
var firstTime = true;
function countdown(minutes) {
var seconds = 60;
var mins = minutes;
if(firstTime && getCookie("minutes")&&getCookie("seconds"))
{
firstTime = false;
var seconds = getCookie("seconds");
var mins = getCookie("minutes");
}
function tick() {
var counter = document.getElementById("timer");
setCookie("minutes",mins,10)
setCookie("seconds",seconds,10)
var current_minutes = mins-1
seconds--;
counter.innerHTML =
current_minutes.toString() + ":" + (seconds < 10 ? "0" : "") + String(seconds);
//save the time in cookie
if( seconds > 0 ) {
setTimeout(tick, 1000);
} else {
if(mins > 1){
// countdown(mins-1); never reach “00″ issue solved:Contributed by Victor Streithorst
setTimeout(function () { countdown(mins - 1); }, 1000);
}
}
}
tick();
}
function setCookie(cname,cvalue,exdays) {
var d = new Date();
d.setTime(d.getTime() + (exdays*24*60*60*1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname+"="+cvalue+"; "+expires;
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1);
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
countdown(55);
</script>
</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="6">no records found</td>
</tr>
{% endfor %}
</tbody>
</table>{% endblock %}
我的 Voiture 实体
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass="App\Repository\VoitureRepository")
*/
class Voiture
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=200)
*/
private $matricule;
/**
* @ORM\Column(type="datetime")
*/
private $gareele;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Parking", inversedBy="voitures")
* @ORM\JoinColumn(nullable=false)
*/
private $parking;
/**
* @ORM\Column(type="boolean")
*/
private $parked;
/**
* @ORM\Column(type="integer")
*/
private $time;
public function getId(): ?int
{
return $this->id;
}
public function getMatricule(): ?string
{
return $this->matricule;
}
public function setMatricule(string $matricule): self
{
$this->matricule = $matricule;
return $this;
}
public function getGareele(): ?\DateTimeInterface
{
return $this->gareele;
}
public function setGareele(\DateTimeInterface $gareele): self
{
$this->gareele = $gareele;
return $this;
}
public function getParking(): ?Parking
{
return $this->parking;
}
public function setParking(?Parking $parking): self
{
$this->parking = $parking;
return $this;
}
public function getParked(): ?bool
{
return $this->parked;
}
public function setParked(bool $parked): self
{
$this->parked = $parked;
return $this;
}
public function getTime(): ?int
{
return $this->time;
}
public function setTime(int $time): self
{
$this->time = $time;
return $this;
}
}
和我的控制器(没什么特别的,只是获取与连接用户相关的停车位):
/**
* @Route("/agent")
*/
class AgentController extends AbstractController
{
/**
* @Route("/", name="agent", methods={"GET"})
*/
public function index(): Response
{
$use = $this->get('security.token_storage')->getToken()->getUser();
$user = $this->getUser();
$parkingz=$this->getUser()->getParkings();
return $this->render('Agent/Agent.html.twig', [
'user' => $user,
'parkingz'=>$parkingz,
]);
}
有重复的 id("test","demo"),每个 voiture 一个。
The id global attribute defines a unique identifier (ID) which must be
unique in the whole document. Its purpose is to identify the element
when linking (using a fragment identifier), scripting, or styling
(with CSS).
这个 document.getElementById("demo")
将要 return 一个结果,可能是 DOM 中的第一个结果。 (我怀疑这里 var test = $('#test').data("isTest");
也是如此,但我并不流利 jQuery)。
也许您可以通过 "name" 属性进行选择,并更改代码以使用一个 <script>
元素来遍历所需的节点。
您有一些嵌套问题(脚本标记需要从 for 循环中出来)、重复的 ID 和不准确的计时系统。如果您需要更新到 real-time,请使用时间戳和系统时钟来确定实际剩余时间。
首先向您的实体添加一个方法来获取过期时间戳(将以秒为单位)
class Voiture
{
...
public function getExpiresAt()
{
$gareele = $this->getGareele();
$expires = clone $gareele;
$expires->modify('+' . $this->getTime() . ' min');
return $expires->format('U');
}
}
然后在模板中,将计时器跨度更改为class="timer"
(不需要id),并添加一个带有到期时间戳的数据属性。该脚本将遍历所有 .timer
并更新文本以反映截至该时刻的剩余天数、小时数、分钟数和秒数。在这里,我通过在函数内部使用 setTimeout()
每 100 毫秒更新一次文本。
{% extends 'Agent/Baseagent.html.twig' %}
{% block title %}Parking index{% endblock %}
{% block body %}
{% for parking in user.parkings %}
<h2>Parking</h2>
{{ parking.libelle }}
<h2>voitures</h2>
<table id="file_export" class="table table-striped table-bordered">
<thead></thead>
<tbody>
{% if parking.voitures|length > 0 %}
{% for voitures in parking.voitures %}
<tr>
<td>
{{ voitures.matricule }}
</td>
<td class="center">
<span class="timer" data-expires="{{ voitures.getExpiresAt() }}"></span>
</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="6">no records found</td>
</tr>
{% endif %}
</tbody>
</table>
{% endfor %}
<script>
var timers = document.querySelectorAll('.timer')
function updateTimers () {
var rightNow = Math.floor(Date.now()/1000) // in seconds
timers.forEach(function (timer) {
var expires = parseInt(timer.dataset.expires) // in seconds
if (rightNow > expires) {
// Time expired
timer.innerText = 'Expired'
} else {
var seconds = expires - rightNow
var minutes = Math.floor(seconds/60)
var hours = Math.floor(minutes/60)
var days = Math.floor(hours/24)
seconds = ('0' + String(seconds%60)).slice(-2)
minutes = ('0' + String(minutes%60)).slice(-2)
hours = ('0' + String(hours%24)).slice(-2)
timer.innerText = days + 'd ' + hours + 'h ' + minutes + 'm ' + seconds + 's'
}
})
setTimeout(function () {
updateTimers()
}, 100)
}
updateTimers()
</script>
{% endblock %}
备注
如果您要通过 ajax 添加更多计时器(在页面加载后),您应该放置以下行:
var timers = document.querySelectorAll('.timer')
在功能块内,在每次调用时搜索新计时器。
我正在使用 Symfony,我目前正在尝试显示数据库中的这些元素,但这里有一个转折点,因为这些元素中的每一个都有持续时间,我必须显示该持续时间的倒计时.
我已经实现了倒计时脚本(尽管它仍然存在一些问题)但它只执行第一个值,而其他行中的字段保持为空。
我现在解释一下代码:我有很多停车场,每个停车场都有很多车(voitures):我的页面显示了停车场,与它们相关的汽车以及每辆车的编号和时间的倒计时那辆车是允许的(时间在数据库的一列中注册)。
我还在我的脚本中使用 cookie 来节省时间,所以我不知道如何为多个值执行此操作。 这是我所做的照片:
这是我的代码(对不起,它很乱):
{% extends 'Agent/Baseagent.html.twig' %}
{% block title %}Parking index{% endblock %}
{% block body %}
{% for parking in user.parkings %}
<h2>Parking</h2>
{{ parking.libelle }}
<h2>voitures</h2>
<table id="file_export" class="table table-striped table-bordered">
<thead>
<tbody>
{% for voitures in parking.voitures %}
<tr>
<td>
{{ voitures.matricule }}
</td>
<td>
<div id="timer" class="js-user-rating" data-is-test="{{ voitures.time}}"></div>
<td class="center"><span id="demo"></span></td>
<script>
var firstTime = true;
function countdown(minutes) {
var seconds = 60;
var mins = minutes;
if(firstTime && getCookie("minutes")&&getCookie("seconds"))
{
firstTime = false;
var seconds = getCookie("seconds");
var mins = getCookie("minutes");
}
function tick() {
var counter = document.getElementById("timer");
setCookie("minutes",mins,10)
setCookie("seconds",seconds,10)
var current_minutes = mins-1
seconds--;
counter.innerHTML =
current_minutes.toString() + ":" + (seconds < 10 ? "0" : "") + String(seconds);
//save the time in cookie
if( seconds > 0 ) {
setTimeout(tick, 1000);
} else {
if(mins > 1){
// countdown(mins-1); never reach “00″ issue solved:Contributed by Victor Streithorst
setTimeout(function () { countdown(mins - 1); }, 1000);
}
}
}
tick();
}
function setCookie(cname,cvalue,exdays) {
var d = new Date();
d.setTime(d.getTime() + (exdays*24*60*60*1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname+"="+cvalue+"; "+expires;
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1);
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
countdown(55);
</script>
</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="6">no records found</td>
</tr>
{% endfor %}
</tbody>
</table>{% endblock %}
我的 Voiture 实体
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass="App\Repository\VoitureRepository")
*/
class Voiture
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=200)
*/
private $matricule;
/**
* @ORM\Column(type="datetime")
*/
private $gareele;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Parking", inversedBy="voitures")
* @ORM\JoinColumn(nullable=false)
*/
private $parking;
/**
* @ORM\Column(type="boolean")
*/
private $parked;
/**
* @ORM\Column(type="integer")
*/
private $time;
public function getId(): ?int
{
return $this->id;
}
public function getMatricule(): ?string
{
return $this->matricule;
}
public function setMatricule(string $matricule): self
{
$this->matricule = $matricule;
return $this;
}
public function getGareele(): ?\DateTimeInterface
{
return $this->gareele;
}
public function setGareele(\DateTimeInterface $gareele): self
{
$this->gareele = $gareele;
return $this;
}
public function getParking(): ?Parking
{
return $this->parking;
}
public function setParking(?Parking $parking): self
{
$this->parking = $parking;
return $this;
}
public function getParked(): ?bool
{
return $this->parked;
}
public function setParked(bool $parked): self
{
$this->parked = $parked;
return $this;
}
public function getTime(): ?int
{
return $this->time;
}
public function setTime(int $time): self
{
$this->time = $time;
return $this;
}
}
和我的控制器(没什么特别的,只是获取与连接用户相关的停车位):
/**
* @Route("/agent")
*/
class AgentController extends AbstractController
{
/**
* @Route("/", name="agent", methods={"GET"})
*/
public function index(): Response
{
$use = $this->get('security.token_storage')->getToken()->getUser();
$user = $this->getUser();
$parkingz=$this->getUser()->getParkings();
return $this->render('Agent/Agent.html.twig', [
'user' => $user,
'parkingz'=>$parkingz,
]);
}
有重复的 id("test","demo"),每个 voiture 一个。
The id global attribute defines a unique identifier (ID) which must be unique in the whole document. Its purpose is to identify the element when linking (using a fragment identifier), scripting, or styling (with CSS).
这个 document.getElementById("demo")
将要 return 一个结果,可能是 DOM 中的第一个结果。 (我怀疑这里 var test = $('#test').data("isTest");
也是如此,但我并不流利 jQuery)。
也许您可以通过 "name" 属性进行选择,并更改代码以使用一个 <script>
元素来遍历所需的节点。
您有一些嵌套问题(脚本标记需要从 for 循环中出来)、重复的 ID 和不准确的计时系统。如果您需要更新到 real-time,请使用时间戳和系统时钟来确定实际剩余时间。
首先向您的实体添加一个方法来获取过期时间戳(将以秒为单位)
class Voiture
{
...
public function getExpiresAt()
{
$gareele = $this->getGareele();
$expires = clone $gareele;
$expires->modify('+' . $this->getTime() . ' min');
return $expires->format('U');
}
}
然后在模板中,将计时器跨度更改为class="timer"
(不需要id),并添加一个带有到期时间戳的数据属性。该脚本将遍历所有 .timer
并更新文本以反映截至该时刻的剩余天数、小时数、分钟数和秒数。在这里,我通过在函数内部使用 setTimeout()
每 100 毫秒更新一次文本。
{% extends 'Agent/Baseagent.html.twig' %}
{% block title %}Parking index{% endblock %}
{% block body %}
{% for parking in user.parkings %}
<h2>Parking</h2>
{{ parking.libelle }}
<h2>voitures</h2>
<table id="file_export" class="table table-striped table-bordered">
<thead></thead>
<tbody>
{% if parking.voitures|length > 0 %}
{% for voitures in parking.voitures %}
<tr>
<td>
{{ voitures.matricule }}
</td>
<td class="center">
<span class="timer" data-expires="{{ voitures.getExpiresAt() }}"></span>
</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="6">no records found</td>
</tr>
{% endif %}
</tbody>
</table>
{% endfor %}
<script>
var timers = document.querySelectorAll('.timer')
function updateTimers () {
var rightNow = Math.floor(Date.now()/1000) // in seconds
timers.forEach(function (timer) {
var expires = parseInt(timer.dataset.expires) // in seconds
if (rightNow > expires) {
// Time expired
timer.innerText = 'Expired'
} else {
var seconds = expires - rightNow
var minutes = Math.floor(seconds/60)
var hours = Math.floor(minutes/60)
var days = Math.floor(hours/24)
seconds = ('0' + String(seconds%60)).slice(-2)
minutes = ('0' + String(minutes%60)).slice(-2)
hours = ('0' + String(hours%24)).slice(-2)
timer.innerText = days + 'd ' + hours + 'h ' + minutes + 'm ' + seconds + 's'
}
})
setTimeout(function () {
updateTimers()
}, 100)
}
updateTimers()
</script>
{% endblock %}
备注
如果您要通过 ajax 添加更多计时器(在页面加载后),您应该放置以下行:
var timers = document.querySelectorAll('.timer')
在功能块内,在每次调用时搜索新计时器。