前言
這關 UI 的部分可以選擇用 CSS 手刻或是直接使用現成的圖片。大部分的時間在處理 UI 的部分,有一個關鍵的 CSS 屬性 transform-origin
,稍後會介紹到,時鐘運作的 JavaScript 相對來說就比較不這麼繁瑣,做一些數學加減運算,配合 Date物件
取得時分秒參數即可。
關卡資訊
- 【特定技術】需使用 JS 原生語法的
getDate()
撈取時間,不可用套件 - 【特定技術】需使用 JS 原生語法的
setTimeout()
或setInterval()
,持續讓秒針、分針、時針能夠以台北時區移動 - 【特定技術】介面請全部用
CSS2
、CSS3
手寫繪製,什麼…?你說太強人所難??那..用圖片也不是不行辣 - 你攻略此 BOSS 的攻略過程心得
解題
時鐘輪廓
將時鐘的輪廓刻出來
HTML
1 | <div class="clock"> |
SCSS
1 | %centerJustify { |
時鐘刻度
接著我們需要把刻度做出來,先不管刻度的樣式和大小,我們知道時鐘總共有 60
個刻度,但是這個設計稿有加一些設計在裡面,每個小時的刻度內各多一個菱形的刻度設計,所以總共的刻度有 60+12=72
個。再來我們需要算出每個小刻度佔幾度,一個圓 360 度,除以刻度數量,得一個刻度為 360/72=5
。
來寫刻度的 CSS 吧,先設定一個父元素 .scale
,裡面會有 72個小刻度 .scale__unit
,不過之後我們會使用 JS 迴圈方式來跑 72 次,不會寫死在 HTML
中,所以先寫一個來設定 CSS 樣式即可。
1 | <div class="clock"> |
1 | .scale { |
transform-origin
上面的程式碼有一個關鍵語法 transform-origin
,可以帶入兩個參數( % ),分別代表 X 與 Y ,這個語法可以改變元素transform 的基準點,若沒有特別設定在 CSS 中,預設的基準點為元素的正中心(下圖第一個例子)。可以參考下面兩個連結,會更容易理解。
transform-origin Demo
clock Demo
時鐘刻度處理及細節
跑迴圈產生 72 個刻度 DOM
1 | function renderClockUnit() { |
小時刻度 & 裝飾刻度樣式
1 | .scale__unit:nth-child(6n+1) { |
到這步,時鐘的刻度算是處理完囉!
製作時鐘上的數字
設計稿上有二十四時制及十二時制的時間,我們先宣告兩個變數分別代表它們
1 | let twelve_hours = 0; // 十二時制 |
接著,只有在小時刻度時會有數字顯示, 接續上面的程式碼,if 陳述句 i%6 == 0
即代表每小時刻度,我們在該條件成立時需渲染時鐘上的數字。
渲染起始點為 12 點的位置,因此當 twelve_hour
跑第一次迴圈時應該為 12
,twenty_hours
則為 24
,其他情況則帶入變數,且每次迴圈變數都要 +1
。
根據上面的代碼,再加入新的功能
1 | if(i%6 == 0) { |
i == 0 ? 12 : twelve_hours
是 JS 的三元運算子,部份情況下可以用簡短的語句取代冗長的if else
,結構為[條件] ? [若true回傳此值] : [false則回傳此值]
我們可以解釋為,當i == 0
( 即第一次迴圈時 ),我要在.twelve
DOM 中輸出 12,其他的情況輸出twelve_hours
變數當前的值。
CSS 樣式
1 | .twelve, .twenty { |
到目前我們的時鐘長這樣,好像還差一點點
將時鐘的數字轉正
這.. 好像很簡單啊? 把 .twelve
和 .twenty
旋轉 180度好像就可以了 ?
1 | .twelve, .twenty { |
記得我們剛剛在處理刻度時,每一個小刻度轉了多少度嗎 ? 5度
,而每一個小時間隔 6 個小刻度,記得吧? 如果要轉正該怎麼做呢 ?
先將剛剛 .twelve
和 .twenty
的 CSS 刪除,我們用迴圈來產生 CSS,首先一樣迴圈起點為旋轉 180 度。
1 | let time_deg = 180; |
每小時間隔 6 個小刻度,每個小刻度為 5 度,因此一次迴圈需要將角度減去 6*5=30
度。
1 | if(i%6 == 0) { |
好的!目前的時鐘長這樣
製作指針
指針部分重點和刻度一樣,善用 transform-origin
來改變 transform 基準點即可。詳細製作過程就不在這邊敘述囉~ 請參考 UI 樣板
時鐘邏輯撰寫
UI 部分搞定了,接著來讓時鐘跑起來吧!!
將指針的 DOM 宣告起來
1 | const hour_hand = document.querySelector('.hand-hour'); |
透過 JS 的 Date
物件抓取時分秒參數
1 | const time = new Date(); |
再來是最關鍵的,將抓到的參數換算成 CSS 的角度,讓時鐘可以正常運作
秒針
sec
變數值的範圍介於0 ~ 60(秒)
,圓為360度
,可以換算得每分鐘的角度為360/60=6 度
。最後需要再扣掉180度
,讓位置以 12 點鐘方向為起點。1
const sec_deg = sec*6 - 180;
分針
分針的概念和秒針相似,不過分針另外還會受到秒數的影響,需另外加上sec*6/60
。1
const min_deg = min*6 + sec*6/60 - 180;
時針
每小時為360/12=30度
,另外加上分鐘數的影響min*6/60
即可。1
const hour_deg = (hour*30 + min*30/60) - 180;
透過 transform: rotate 為指針 DOM 套用角度
1 | hour_hand.style.transform = `rotate(${ hour_deg }deg)`; |
setInterval 重複執行
將上面整理的邏輯包裝成函式
1 | function clockPrimaryFeature() { |
執行
1 | function runClock(callback){ |
Codepen Demo
See the Pen JS地下城 - 2F 時鐘 VanillaJS by Dylan (@Dylan_Liu) on CodePen.