成品連結:JS & CSS Clock
來到第二天啦!今天要做的是時鐘,話不多說,我們就開始吧~
先看一下 HTML & CSS 程式碼
首先我們要先設定指針旋轉軸心,設定在指針的最右側(想像指針位置目前都在 9 點鐘位置),接著希望把指針調整至12點鐘位置為起點,所以會這樣寫:
/* hand 是三種指針的共同 class */
.hand {
transform-origin: 100%;
transform: rotate(90deg);
}
首先使用transform-origin
將旋轉軸心設定在 X 軸最右側,並使用rotate
調整旋轉角度
接著我希望當指針進位時可以能像真實時鐘有抖動的感覺,可以透過調整transition-timing-function
做到
transition-timing-function: cubic-bezier(0.1, 2.7, 0.58, 1);
括號內的數字不是絕對的,大家可以透過 chrome 控制台調整喜歡的感覺後再複製到自己的 CSS 檔案內,如果懶的話也可以套用預設的 ease-in、ease-out等樣式
接著就可以開始寫 JS 了!
使用 new Date() 取得目前的時、分、秒!
// 時針、分針、秒針
const secondHand = document.querySelector('.second-hand');
const minuteHand = document.querySelector('.min-hand');
const hourHand = document.querySelector('.hour-hand');
setClock() {
const cutrrentTime = new Date();
const second = currentTime.getSeconds();
const minute = currentTime.getMinutes();
const hour = currentTime.getHours();
}
可以試著在 console 使用 Date(),會發現會印出當前時間,但如果我們想要存取並使用的話,就必需使用 new
和宣告變數來操作(若只有用 Date()那只會印出目前時間的字串)
接著計算秒針、分針、時針每秒/分/時會移動的角度並渲染到 HTML 上
const cutrrentTime = new Date();
const second = currentTime.getSeconds();
const minute = currentTime.getMinutes();
const hour = currentTime.getHours();
setClock() {
const secondDegrees = ((second / 60) * 360) + 90;
const minuteDegrees = ((minute / 60) * 360) + ((second / 60) * 6) + 90;
const hourDegrees = ((hour / 12) * 360) + ((minute / 60) * 30) + 90;
secondHand.style.transform = `rotate(${secondDegrees}deg)`;
minuteHand.style.transform = `rotate(${minuteDegrees}deg)`;
hourHand.style.transform = `rotate(${hourDegrees}deg)`;
}
可以注意到計算角度時分針及秒針分別加了((second / 60) * 6)
和((minute / 60) * 30)
來模擬真實時鐘的分針、時針會隨著秒針及分針前進而移動一些些
接著設定每秒更新畫面,這裡使用setInterval
,並在第一個參數傳入setClock
函式,並在第二個參數設定更新時間,這裡設定每秒更新,也就是1000(毫秒)
setInterval(setClock, 1000);
至此基本功能已具備,但是!
當秒針、分針、時針走了一圈時,會發現有不明抖動感覺,其實是因為我們 CSS 用了transition
,而當秒針走完一圈後秒數從 60 變成 0,所以當把transition
時間拉長後會看到其實秒針是倒轉了一圈,而不是正常的前進一格
應該會有不少方法可以解決,這裡我想到的是一開始設定時間,接著使用計時器增加秒數,並一併調整分針及時針。如此就可以解決秒、分、時走一圈後歸零的狀況
let secondCount = 0;
function updateClock() {
secondCount++;
const newSecond = currentTime.getSeconds() + secondCount;
const secondDegrees = (newSecond) * 6 + 90;
let minuteDegrees, hourDegrees;
secondHand.style.transform = `rotate(${secondDegrees}deg)`;
minuteDegrees = ((minute / 60) * 360) + ((newSecond / 60) * 6) + 90;
minuteHand.style.transform = `rotate(${minuteDegrees}deg)`;
hourDegrees = ((hour / 12) * 360) + (minute / 60 * 30) + ((newSecond / 3600) * 30) + 90;
hourHand.style.transform = `rotate(${hourDegrees}deg)`;
}
並修改一下呼叫函式的順序
// 首先先設定目前時間
setClock();
// 接著每秒更新時鐘
window.setInterval(updateClock, 1000);
這裡寫了一個變數secondCount
來記錄新增秒數,和一個函式updateClock
來更新時間,分針和時針也會隨秒針移動而前進一些些。
雖然原本問題解決了,但因為secondCount
會不斷增加,所以當時鐘放置很長一段時間後會變成一個超過 JS 能記錄的最大數字並發生錯誤...但目前想不到更好做法了,如果有想到會再更新在這裡~