iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 30
1
Modern Web

寫JS30天系列 第 30

JS30 - 30 - Countdown Timer

今天要來做一個倒數計時器,首先我們先將所有的 buttons都監聽起來,在點擊後,抓到設定的時間並當成參數傳入 timer() ,再抓到要顯示的區域。

const timerButtons = document.querySelectorAll('.timer__button');
const displayTimeLeft = document.querySelector('.display__time-left');
const displayEndTime = document.querySelector('.display__end-time');

function timerStart() {
    const timeDiff = Number(this.dataset.time);
    timer(timeDiff);
}

timerButtons.forEach(btn => btn.addEventListener('click', timerStart));

接著我們要設定一秒一次的計時器 timer, 我們目前掌握兩件事「顯示剩餘時間」(一秒一次)和「顯示結束時間」(一次),全部都用毫秒來算才不用判別進位問題。如果剩餘秒數小於0,就清掉計時器並 return

function timer(timeDiff) {
    const now = new Date().getTime(); //取得1970到現在的毫秒
    const nowSec = Math.round(now / 1000); //換成秒
    const endMillionSec = (nowSec + timeDiff) * 1000; //結束毫秒數

    showTimeLeft(timeDiff); //顯示剩餘時間
    showEndTime(endMillionSec); //顯示結束時間
    let countDown = setInterval(function () {
        secondLeft = Math.round((endMillionSec - Date.now()) / 1000);
        if (secondLeft < 0) {
            clearInterval(countDown);
            return;
        }
        showTimeLeft(secondLeft); //刷新剩餘時間
    }, 1000);
}

寫完上列程式碼,還不會跑起來,先把 showEndTime() 註解掉,我們先來處理 showLeftTime(),首先我們將傳進去的秒數整理成分跟秒,最後再渲染上 html

function showTimeLeft(secondLeft) {
    const minLeft = Math.floor(secondLeft / 60);
    secondLeft %= 60;
    const timeLeft = `${minLeft}:${secondLeft}`;
    displayTimeLeft.textContent = timeLeft;
}

處理完後會發現如果連續點擊時間按鈕會有多個計時器在計時,顯示剩餘時間會跳來跳去。
這時候要修改一下,每次在設置 timer 時,先把計時器清掉。因此必須在 function 外宣告,不然會找不到 countDown 這個變數。

let countDown; //在外面宣告
function timer(timeDiff) {
    clearInterval(countDown);//清掉計時器
    const now = new Date().getTime(); 
    const nowSec = Math.round(now / 1000); 
    const endMillionSec = (nowSec + timeDiff) * 1000; 

    showTimeLeft(timeDiff); 
    showEndTime(endMillionSec); 
    countDown = setInterval(function () { //不需要宣告
        secondLeft = Math.round((endMillionSec - Date.now()) / 1000);
        if (secondLeft < 0) {
            clearInterval(countDown);
            return;
        }
        showTimeLeft(secondLeft); 
    }, 1000);
}

接著我們要顯示截止時間new Date(value),放入結束毫秒的 value ,即可拿到結束的時間。
再將時間渲染上去。

function showEndTime(endMillionSec) {
    const end = new Date(endMillionSec)
    let endHr = end.getHours();
    let endMin = end.getMinutes();
    const endTime = `計時器將在${endHr}:${endMin}到期`;
    displayEndTime.textContent = endTime;
}

現在可以來跑看看成果了!會發現還是有問題,當秒針是個位數的時候顯示的不是兩位數。
因此我們要判斷當秒數小於10的時候,會在前面補0。

function showTimeLeft(secondLeft) {
    ...
    const timeLeft = `${minLeft}:${secondLeft < 10 ? '0': ''}${secondLeft}`;
    displayTimeLeft.textContent = timeLeft;
}
function showEndTime(endMillionSec) {
    ...
    const endTime = `計時器將在${endHr}:${endMin < 10 ? '0':''}${endMin}到期`;
    displayEndTime.textContent = endTime;
}

最後我們要監聽submit事件,要注意的是 submit 事件只有在 form 元素有效, input[type=text] 元素不能被監聽 submit 事件,當 submit 事件發生,擷取輸入值並執行計時器

const minInput = document.querySelector('#custom');
function showEndTime(endMillionSec) {
    minInput.addEventListener('submit', function (e) {
    e.preventDefault();
    const timeDiff = this.minutes.value;
    timer(timeDiff * 60);
    this.reset();
    });
}

Demo
完整程式碼


上一篇
JS30 - 29 - Video Speed Controller
系列文
寫JS30天30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

我要留言

立即登入留言