倒计时案例

148 阅读1分钟

/*

  • 两个时间:
    • 目标时间 18:00:00
    • 当前时间
  • 目标时间-当前时间=时间差 「毫秒差:计算时间差中包含多少小时,多少分钟,多少秒」
  • 每间隔一秒中都需要重新获取当前时间「定时器 setInterval」,重算时间差等
  • 核心的问题:
  • 当前时间是不可以获取客户端本地的(因为本地的时间客户自己可以肆意的修改),需要统一获取服务器的时间「响应头->Date」
    • 获取服务器时间会存在时间偏差问题 --> HEAD AJAX状态码为2
  • 在页面不刷新的情况下,每间隔1秒,不是再次从服务器获取(如果这样:服务器会崩溃,用户得到的时间误差也会越大...),而是基于第一次获取的结果之上,手动给其累加1000ms即可 */

1、js代码

let countdownModule = (function () {
let textBox = document.querySelector('.text'),
    serverTime = 0,
    targetTime = +new Date('2020/12/05 16:00:00'),
    timer = null;

// 获取服务器时间
const queryServerTime = function queryServerTime() {
    return new Promise(resolve => {
        let xhr = new XMLHttpRequest;
        xhr.open('HEAD', '/');
        xhr.onreadystatechange = () => {
            if ((xhr.status >= 200 && xhr.status < 300) && xhr.readyState === 2) {
                let time = xhr.getResponseHeader('Date');
                // 获取的时间是格林尼治时间 -> 变为北京时间
                resolve(+new Date(time));
            }
        };
        xhr.send(null);
    });
};

// 倒计时计算
const supplyZero = function supplyZero(val) {
    val = +val || 0;
    return val < 10 ? `0${val}` : val;
};
const computed = function computed() {
    let diff = targetTime - serverTime,
        hours = 0,
        minutes = 0,
        seconds = 0;
    if (diff <= 0) {
        // 到达抢购时间了
        textBox.innerHTML = '00:00:00';
        clearInterval(timer);
        return;
    }
    // 没到时间则计算即可
    hours = Math.floor(diff / (1000 * 60 * 60));
    diff = diff - hours * 1000 * 60 * 60;
    minutes = Math.floor(diff / (1000 * 60));
    diff = diff - minutes * 1000 * 60;
    seconds = Math.floor(diff / 1000);
    textBox.innerHTML = `${supplyZero(hours)}:${supplyZero(minutes)}:${supplyZero(seconds)}`;
};

return {
    async init() {
        serverTime = await queryServerTime();
        computed();

        // 设置定时器   
        timer = setInterval(() => {
            serverTime += 1000;
            computed();
        }, 1000);
    }
};
})();
countdownModule.init();

2、html页面

  <!DOCTYPE html>
  <html>

  <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>珠峰在线Web高级</title>
      <style>
          * {
              margin: 0;
              padding: 0;
          }

          .box {
              width: 300px;
              height: 50px;
              line-height: 50px;
              text-align: center;
              background: lightblue;
              letter-spacing: 3px;
          }

          .box .text {
              color: red;
          }
      </style>
  </head>

  <body>
      <div class="box">
          距离抢购还剩下
          <span class="text">00:00:00</span>
      </div>

      <script src="2.js"></script>
  </body>

  </html>