尽管倒计时 TS、JS 运行,但 DOM 不会自动更新

问题描述 投票:0回答:1

问题: 我正在使用 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
;

的方法

问题:

  1. 如何确保 DOM 随着倒计时的进行自动更新?
  2. 使用倒计时器实时更新 DOM 有什么具体注意事项或最佳实践吗?

任何有关解决此问题的见解或建议将不胜感激。

javascript typescript dom
1个回答
0
投票

您的问题是

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>

© www.soinside.com 2019 - 2024. All rights reserved.