JS30 day29 Countdown Timer
JS30 day29 - Countdown Timer
作業內容
今天的作業是做出一個倒數的頁面,有按鈕可按,也可以自訂要倒數幾分鐘
雖然聽起來頗為簡單,但做起來要超多細節要注意
可以看這份 codepen

學到什麼
- JS
1.
直覺想到倒數的功能是使用 setInterval
可是這會有幾個比較不友好的點:比方說在 ios 上面 scroll 的時候他自動會把這功能停掉,你滾動 10 秒的話倒數就少了 10 秒,所以建議不要在這邊用 setInterval
function timer(seconds){ setInterval(function(){ seconds--; }, 1000) }- 讓 setInterval 在倒數完之後不繼續運作 最直覺想到的可能會是這樣:
但 return 不能真正解決問題,他只是不繼續往下執行,每秒還是會觸發這個事件,所以要用 cleanInterval 我們要在他自己的方法裡面停掉自己,所以先做出一個 global 的 coundown 變數再用 clearInterval 停掉它setInterval(function(){ const secondsLeft = Math.round((then - Date.now()) / 1000) if(secondsLeft < 0) return; console.log(secondsLeft) }, 1000)let countdown function timer(seconds){ // const now = (new Date()).getTime() // 上面這種寫法也可以 const now = Date.now() // mili seconds 的形式 const then = now + seconds * 1000 countdown = setInterval(function(){ const secondsLeft = Math.round((then - Date.now()) / 1000) if(secondsLeft < 0) { clearInterval(countdown) return } console.log(secondsLeft) }, 1000) }- 有個很細節的地方:目前我們呼叫 timer 的時候,他當下不會觸發時間,而是過一秒之後才開始,可以看下圖,想要的效果是如果呼叫
timer(10)當下會先說出 10
因此我們要改成這樣
function timer(seconds){ // const now = (new Date()).getTime() // 上面這種寫法也可以 const now = Date.now() // mili seconds 的形式 const then = now + seconds * 1000 displayTimeLeft(seconds) countdown = setInterval(function(){ const secondsLeft = Math.round((then - Date.now()) / 1000) if(secondsLeft < 0) { clearInterval(countdown) return } displayTimeLeft(secondsLeft) }, 1000) } function displayTimeLeft(seconds){ console.log(seconds) }- 如果在按下一個 timer 又按另一個 timer 之後,這些 setInterval 的效果會疊加,所以在開始另一個之前要先把先前的停掉
function timer(seconds){ // 開始另一個 timer 之前先把之前的 setInterval 停掉 clearInterval(countdown) // 下略- 我們可以直接用
document.<form 的 name>這個方式來呼叫 form,可以再用一層呼叫 input 的 name
<form name="customForm" id="custom"> <input type="text" name="minutes" placeholder="Enter Minutes"> </form>document.customForm // <form name="customForm" id="custom"> document.customForm.minutes // <input type="text" name="minutes" placeholder="Enter Minutes">
https://github.com/wesbos/JavaScript30
code 內容:
HTML:
<div class="timer">
<div class="timer__controls">
<button data-time="20" class="timer__button">20 Secs</button>
<button data-time="300" class="timer__button">Work 5</button>
<button data-time="900" class="timer__button">Quick 15</button>
<button data-time="1200" class="timer__button">Snack 20</button>
<button data-time="3600" class="timer__button">Lunch Break</button>
<form name="customForm" id="custom">
<input type="text" name="minutes" placeholder="Enter Minutes">
</form>
</div>
<div class="display">
<h1 class="display__time-left"></h1>
<p class="display__end-time"></p>
</div>
</div>
CSS:
html {
box-sizing: border-box;
font-size: 10px;
background: #8E24AA;
background: linear-gradient(45deg, #42a5f5 0%,#478ed1 50%,#0d47a1 100%);
}
*, *:before, *:after {
box-sizing: inherit;
}
body {
margin: 0;
text-align: center;
font-family: 'Inconsolata', monospace;
}
.display__time-left {
font-weight: 100;
font-size: 20rem;
margin: 0;
color: white;
text-shadow: 4px 4px 0 rgba(0,0,0,0.05);
}
.timer {
display: flex;
min-height: 100vh;
flex-direction: column;
}
.timer__controls {
display: flex;
}
.timer__controls > * {
flex: 1;
}
.timer__controls form {
flex: 1;
display: flex;
}
.timer__controls input {
flex: 1;
border: 0;
padding: 2rem;
}
.timer__button {
background: none;
border: 0;
cursor: pointer;
color: white;
font-size: 2rem;
text-transform: uppercase;
background: rgba(0,0,0,0.1);
border-bottom: 3px solid rgba(0,0,0,0.2);
border-right: 1px solid rgba(0,0,0,0.2);
padding: 1rem;
font-family: 'Inconsolata', monospace;
}
.timer__button:hover,
.timer__button:focus {
background: rgba(0,0,0,0.2);
outline: 0;
}
.display {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.display__end-time {
font-size: 4rem;
color: white;
}
JS:
let countdown
const timerDisplay = document.querySelector('.display__time-left')
const endTime = document.querySelector('.display__end-time')
const buttons = document.querySelectorAll('[data-time]')
function timer(seconds){
// 開始另一個 timer 之前先把之前的 setInterval 停掉
clearInterval(countdown)
// const now = (new Date()).getTime()
// 上面這種寫法也可以
const now = Date.now() // mili seconds 的形式
const then = now + seconds * 1000
displayEndTime(then)
displayTimeLeft(seconds)
countdown = setInterval(function(){
const secondsLeft = Math.round((then - Date.now()) / 1000)
if(secondsLeft < 0) {
clearInterval(countdown)
return
}
displayTimeLeft(secondsLeft)
}, 1000)
}
function displayTimeLeft(seconds){
const minutes = Math.floor(seconds / 60)
const remainSeconds = seconds % 60
const display = `${minutes}:${remainSeconds < 10 ? '0' : ''}${remainSeconds}`
document.title = display
timerDisplay.textContent = display
}
function displayEndTime(timestamp){
const end = new Date(timestamp)
const hours = end.getHours()
const minutes = end.getMinutes()
endTime.textContent = `Be Back At ${hours}:${minutes < 10 ? '0' : ''}${minutes}`
}
function startTimer(){
const period = this.dataset.time
timer(period)
}
buttons.forEach(button => button.addEventListener('click', startTimer))
document.customForm.addEventListener('submit', function(e){
e.preventDefault()
const mins = this.minutes.value
timer(mins * 60)
this.reset()
})