iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 2
0

成品連結:JS & CSS Clock

來到第二天啦!今天要做的是時鐘,話不多說,我們就開始吧~

事前準備

步驟

  • 設定每秒更新畫面(setInterval)
    • 取得目前時間並印出
    • 更新畫面

先看一下 HTML & CSS 程式碼

開始寫程式碼

CSS transform & transition

首先我們要先設定指針旋轉軸心,設定在指針的最右側(想像指針位置目前都在 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 了!

Date()

使用 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()

接著設定每秒更新畫面,這裡使用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 能記錄的最大數字並發生錯誤...但目前想不到更好做法了,如果有想到會再更新在這裡~

Reference


上一篇
JS30 Day 1 - Drum Kit
下一篇
JS30 Day 3 - CSS Variables
系列文
一起挑戰 JavaScript 30 吧!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言