javascript - 一个重复的倒数计时器,即使在浏览器刷新后也会继续
问题描述
首先,我对 javascript 非常陌生。我有一个 Shopify 商店,我计划像亚马逊一样为我的每个产品页面设置一个倒数计时器。我知道有很多插件可以用于 Shopify,但它们都不符合我 Shopify 商店的主题和风格,所以我打算自己制作一个。
我想要的是,如果用户 1 打开我的网站并导航到产品页面,他应该会看到一个倒计时到特定时间的计时器12:00:00
(hh:mm:ss)。假设 User-1 看到 ' Deal ends in 11:20:10
' 现在如果 User-2 同时打开同一个产品页面,那么他也应该看到 ' Deal ends in 11:20:10
' 重点是计时器不应该在12:00:00
每次浏览器加载/重新加载页面时刷新网站上的用户应该看到倒数计时器上的剩余时间相同。
我从一些研究开始,并设法在我的商店里运行了一个计时器。这不完全是我想要的,但这里是代码:
var interval;
var minutes = 1;
var seconds = 5;
window.onload = function() {
countdown('countdown');
}
function countdown(element) {
interval = setInterval(function() {
var el = document.getElementById(element);
if(seconds == 0) {
if(minutes == 0) {
el.innerHTML = "countdown's over!";
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 ? 'seconds' : 'second';
el.innerHTML = minute_text + ' ' + seconds + ' ' + second_text + ' remaining';
seconds--;
}, 1000);
}
</script>
这就是它的样子:
它确实有效,但存在以下问题:
- 它随着浏览器刷新而刷新。
- 它没有时间。
- 当计时器达到零时,它不会自动重复。
- 对于每个用户的剩余时间都不同。
正如我所提到的,我几乎是 JavaScript 的菜鸟。谁能帮我建立一个可以克服上述问题的倒数计时器?
解决方案
解释
问题1:它随着浏览器刷新而刷新。
原因:因为您对秒和分钟 ( var seconds = 5
, var minutes = 1
) 进行了硬编码,所以访问该页面的每个用户都会看到计时器从完全相同的值“剩余 1 分 5 秒”一次又一次地倒计时。
解决方案:与其硬编码倒计时的起始值,不如硬编码截止日期。因此,不要对页面的每个访问者说“从 1 分 5 秒开始倒计时到 0!”,而必须说“从现在到午夜的任何时间倒计时!”。这样,倒计时将始终在您网站的不同用户之间同步(假设他们的计算机时钟设置正确)。
问题 2:它没有时间。
原因:您的代码只有变量来跟踪秒和分钟,没有编写代码来跟踪小时。
解决方案:就像问题1的解决方案中提出的那样:不跟踪剩余的小时/分钟/秒,而只跟踪截止日期,然后根据当前客户端时间计算剩余的小时/分钟/秒。
问题 3:当计时器归零时,它不会自动重复。
原因:代码中的嵌套if
s(检查seconds == 0
和m == 0
)明确声明显示文本“倒计时结束!” 当倒计时结束时。
解决方案:保留一个条件来检查倒计时何时结束,而不是显示“倒计时结束!”,将截止日期重置为下一个截止日期。
问题 4:每个用户的剩余时间各不相同。
原因:见问题 1
解决方案:见问题 1
示例代码
这是一段集成了上述解决方案的代码:
const span = document.getElementById('countdown')
const deadline = new Date
deadline.setHours(0)
deadline.setMinutes(0)
deadline.setSeconds(0)
function displayRemainingTime() {
if (deadline < new Date) deadline.setDate(deadline.getDate() + 1)
const remainingTime = deadline - new Date
const extract = (maximum, factor) => Math.floor((remainingTime % maximum) / factor)
const seconds = extract( 60000, 1000 )
const minutes = extract( 3600000, 60000 )
const hours = extract(86400000, 3600000)
const string = `${hours} hours ${minutes} minutes ${seconds} seconds remaining`
span.innerText = `${hours} hours ${minutes} minutes ${seconds} seconds remaining`
}
window.setInterval(displayRemainingTime, 1000)
displayRemainingTime()
<h3>
<span id="countdown"></span>
</h3>
编辑:确保客户端时间正确
如果您不信任您的客户正确设置他们的时间。您还可以从为您的页面提供服务的服务器发送正确的时间戳。由于我不知道您使用的是哪种服务器,因此我无法为您的服务器代码提供示例。但基本上,您需要用您在服务器上生成的正确时间戳替换const trustedTimestamp =
(being ) 之后的代码(来自以下示例)。(new Date).getTime()
有关此时间戳的正确格式,请参阅Date.prototype.getTime()
const span = document.getElementById('countdown')
const trustedTimestamp = (new Date).getTime()
let timeDrift = trustedTimestamp - (new Date)
const now = () => new Date(timeDrift + (new Date).getTime())
const deadline = now()
deadline.setHours(0)
deadline.setMinutes(0)
deadline.setSeconds(0)
function displayRemainingTime() {
if (deadline < now()) deadline.setDate(deadline.getDate() + 1)
const remainingTime = deadline - now()
const extract = (maximum, factor) => Math.floor((remainingTime % maximum) / factor)
const seconds = extract( 60000, 1000 )
const minutes = extract( 3600000, 60000 )
const hours = extract(86400000, 3600000)
span.innerText = `${hours} hours ${minutes} minutes ${seconds} seconds remaining`
}
window.setInterval(displayRemainingTime, 1000)
displayRemainingTime()
<h3>
<span id="countdown"></span>
</h3>
来自谷歌服务器的时间
为了创建一个工作示例,我添加了这个实验,我从 Google 页面获得了正确的时间。不要在您的网站上使用此代码,因为不能保证 google 将永远托管此网页。
const span = document.getElementById('countdown')
const trustedTimestamp = (new Date).getTime()
let timeDrift = 0
const now = () => new Date(timeDrift + (new Date).getTime())
const deadline = now()
deadline.setHours(0)
deadline.setMinutes(0)
deadline.setSeconds(0)
window.setInterval(displayRemainingTime, 1000)
window.setInterval(syncClock, 3000)
displayRemainingTime()
syncClock()
function displayRemainingTime() {
if (deadline < now()) deadline.setDate(deadline.getDate() + 1)
const remainingTime = deadline - now()
const extract = (maximum, factor) => Math.floor((remainingTime % maximum) / factor)
const seconds = extract( 60000, 1000 )
const minutes = extract( 3600000, 60000 )
const hours = extract(86400000, 3600000)
span.innerText = `${hours} hours ${minutes} minutes ${seconds} seconds remaining`
}
function syncClock() {
const xmlhttp = new XMLHttpRequest();
xmlhttp.open("HEAD", "http://www.googleapis.com",true);
xmlhttp.onreadystatechange = function() {
const referenceTime = new Date
if (xmlhttp.readyState==4) {
const correctTime = new Date(xmlhttp.getResponseHeader("Date"))
timeDrift = correctTime - referenceTime
}
}
xmlhttp.send(null);
}
<h3>
<span id="countdown"></span>
</h3>
推荐阅读
- python - 熊猫:带有方程式的Excel单元格在熊猫read_excel()中给出“0”
- android - 添加 google admob 依赖项后我无法构建我的项目
- c# - 访问 xamarin.form Android 10 sd 卡
- laravel - 在 Datatables 中添加按钮 // 打开按钮以打开另一个布局
- reactjs - 在反应中使用 FormData() 不断返回 null
- editor - 使用 Atom 运行 C 程序
- docker - 使用容器的 Azure DevOps 作业步骤
- sql - 将多行串联成单列,最大行数限制为 1000
- heroku - 在heroku中运行时有什么方法可以获取应用程序名称吗?
- css - 添加 svg 作为伪元素