问题: 我正在使用 JavaScript 开发一个倒计时器,该功能似乎运行良好。但是,我遇到了 DOM 不会自动更新的问题。我尝试过以各种方式和地点使用
setInterval
,但问题仍然存在。
我对 JavaScript 和 TypeScript 比较陌生,请耐心等待,(我在不使用类的情况下解决了这个问题,我想让这个类供其他项目参考)
代码概述: 我有一个
CountdownDate
类,其中包含计算剩余天数、小时、分钟和秒的方法。倒计时本身在特定日期启动,目标是动态更新 DOM。
问题: 倒计时本身是准确的,并且控制台日志显示正确的值。尽管如此,DOM 上显示的值并没有实时更新。
尝试解决: 我尝试使用
setInterval
以一秒的间隔更新剩余时间。此外,我在 setTimeout
方法中使用了 app
来检查倒计时是否已结束。尽管做出了这些努力,DOM 似乎并未反映更新后的值。
代码片段:
type Months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
type Weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
const months: Months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
const weekdays: Weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
const sold = document.querySelector<HTMLHeadingElement>('.sold');
const deadline = document.querySelector<HTMLDivElement>('.deadline');
const items = document.querySelectorAll<HTMLHeadingElement>('.deadline-format .times');
class CountdownDate {
constructor(
public year: number = 0,
public month: number = 1,
public day: number = 1,
public hours: number = 0,
public minutes: number = 0,
public seconds: number = 0,
public startedDate: Date = new Date(),
public targetDate: Date = new Date(year, month - 1, day, hours, minutes, seconds),
public startedTime: number = startedDate.getTime(),
public RemainingTime: number = targetDate.getTime() - startedDate.getTime(),
) { }
private static staticTime(t?: 'year' | 'month' | 'hour' | 'min'): number {
if (t === 'hour') {
return 60 * 60 * 1000;
} else if (t === 'min') {
return 60 * 1000;
}
return 24 * 60 * 60 * 1000; // Default to days
}
get RemainingDays(): number {
let oneDay = CountdownDate.staticTime();
return Math.floor(this.RemainingTime / oneDay);
}
get RemainingHours(): number {
let oneDay = CountdownDate.staticTime();
let oneHour = CountdownDate.staticTime('hour');
return Math.floor((this.RemainingTime % oneDay) / oneHour);
}
get RemainingMinutes(): number {
let oneMinute = CountdownDate.staticTime('min');
let oneHour = CountdownDate.staticTime('hour');
return Math.floor((this.RemainingTime % oneHour) / oneMinute);
}
get RemainingSeconds(): number {
let oneMinute = CountdownDate.staticTime('min');
return Math.floor((this.RemainingTime % oneMinute) / 1000);
}
public countedTime() {
let arrTimes = [
countdownDate.RemainingDays,
countdownDate.RemainingHours,
countdownDate.RemainingMinutes,
countdownDate.RemainingSeconds,
];
return arrTimes
}
get check() {
return this.RemainingTime < 0;
}
app(callback: any) {
if (this.check) {
clearInterval(callback);
deadline!.innerHTML = '<b>Sorry, the time has expired!</b>';
} else {
setInterval(callback, 1000);
return this.countedTime;
}
}
}
let countdownDate = new CountdownDate(2024, 3, 1);
const year = countdownDate.targetDate.getFullYear();
const hours = countdownDate.targetDate.getHours();
const minutes = countdownDate.targetDate.getMinutes();
const month = months[countdownDate.targetDate.getMonth()];
const date = countdownDate.targetDate.getDay();
const dayWeek = weekdays[date];
if (sold) {
sold.textContent = `
sold Ends On ${dayWeek}, ${date} ${month} ${year} ${hours}:${minutes}am
`;
} else {
throw new Error("'sold' is undefined");
}
function updateDom() {
let values = countdownDate.countedTime();
items.forEach((item, i) => {
item.textContent = String(values[i]);
});
}
countdownDate.app(updateDom);
我尝试通过创建一个方法并将其注入到
RemainingTime
中来更新
updateDom()
class CountdownDate {
/// con
updateRemainingTime(): void {
setInterval(() => {
this.RemainingTime = this.targetDate.getTime() - this.startedDate.getTime();
}, 1000);
}
}
function updateDom() {
countdownDate.updateRemainingTime()
let values = countdownDate.countedTime();
items.forEach((item, i) => {
item.textContent = String(values[i]);
});
}
以及太多其他使用
setInterval
; 的方法
问题:
任何有关解决此问题的见解或建议将不胜感激。
您的问题是
RemainingTime
没有改变。在第一个示例中, RemainingTime
是在构造函数触发时计算的,然后从那时起不再更新。在您的另一个例子中,您尝试在循环中更新 RemainingTime
,您没有考虑到 startedDate
是一个也不会改变的固定值。因此计算将始终产生相同的数字,因为 startedDate
也仅在构造函数中设置,因此它并不代表当前时间。我建议使用您的第一个示例,但为 RemainingTime
创建一个吸气剂,以便您可以在访问它时计算它,如下所示:
get RemainingTime() {
const offsetDate = Math.max(this.startedDate, new Date());
return this.targetDate.getTime() - offsetDate;
}
注意这只是一个示例,我取当前时间和开始日期之间的最大值。如果开始日期是将来的日期,则倒计时不会倒计时,但您可以将此行为和计算修改为您的预期行为。
const months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
const weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
const sold = document.querySelector('.sold');
const deadline = document.querySelector('.deadline');
const items = document.querySelectorAll('.deadline-format .times');
class CountdownDate {
constructor(
year = 0,
month = 1,
day = 1,
hours = 0,
minutes = 0,
seconds = 0,
startedDate = new Date(),
targetDate = new Date(year, month - 1, day, hours, minutes, seconds),
startedTime = startedDate.getTime()
) {
this.year = year;
this.month = month;
this.day = day;
this.hours = hours;
this.minutes = minutes;
this.seconds = seconds;
this.startedDate = startedDate;
this.targetDate = targetDate;
this.startedTime = startedTime;
}
static staticTime(t) {
if (t === 'hour') {
return 60 * 60 * 1000;
} else if (t === 'min') {
return 60 * 1000;
}
return 24 * 60 * 60 * 1000; // Default to days
}
get RemainingDays() {
let oneDay = CountdownDate.staticTime();
return Math.floor(this.RemainingTime / oneDay);
}
get RemainingHours() {
let oneDay = CountdownDate.staticTime();
let oneHour = CountdownDate.staticTime('hour');
return Math.floor((this.RemainingTime % oneDay) / oneHour);
}
get RemainingMinutes() {
let oneMinute = CountdownDate.staticTime('min');
let oneHour = CountdownDate.staticTime('hour');
return Math.floor((this.RemainingTime % oneHour) / oneMinute);
}
get RemainingSeconds() {
let oneMinute = CountdownDate.staticTime('min');
return Math.floor((this.RemainingTime % oneMinute) / 1000);
}
countedTime() {
let arrTimes = [
countdownDate.RemainingDays,
countdownDate.RemainingHours,
countdownDate.RemainingMinutes,
countdownDate.RemainingSeconds,
];
return arrTimes
}
get check() {
return this.RemainingTime < 0;
}
app(callback) {
if (this.check) {
clearInterval(callback);
deadline.innerHTML = '<b>Sorry, the time has expired!</b>';
} else {
setInterval(callback, 1000);
return this.countedTime;
}
}
get RemainingTime() {
const offsetDate = Math.max(this.startedDate, new Date());
return this.targetDate.getTime() - offsetDate;
}
}
let countdownDate = new CountdownDate(2024, 3, 1);
const year = countdownDate.targetDate.getFullYear();
const hours = countdownDate.targetDate.getHours();
const minutes = countdownDate.targetDate.getMinutes();
const month = months[countdownDate.targetDate.getMonth()];
const date = countdownDate.targetDate.getDay();
const dayWeek = weekdays[date];
if (sold) {
sold.textContent = `
sold Ends On ${dayWeek}, ${date} ${month} ${year} ${hours}:${minutes}am
`;
} else {
throw new Error("'sold' is undefined");
}
function updateDom() {
let values = countdownDate.countedTime();
items.forEach((item, i) => {
item.textContent = String(values[i]);
});
}
countdownDate.app(updateDom);
<h1 class="sold"></h1>
<div class="deadline"></div>
<div class="deadline-format">
Days: <h4 class="times"></h4>
Hours: <h4 class="times"></h4>
Minutes: <h4 class="times"></h4>
Seconds: <h4 class="times"></h4>
</div>