# Day2: JS and CSS Clock [竹白記事本](https://chupainotebook.blogspot.com/),Javascript 30,紀錄。 ###### tags: `Javascript 30` ## 實現效果 用 JS 與 CSS 搭配製作一個實時的時鐘效果。 - [原始碼](https://github.com/chupai/JS30/tree/master/source_code/Day02) - [原始狀態](https://chupai.github.io/JS30/source_code/Day02/index-START.html) - [範例效果](https://chupai.github.io/JS30/source_code/Day02/index-FINISHED.html) ## 重點 - 建立指針 CSS 樣式 - 取得指針 DOM - 建立控制時鐘函式 - 取得現在時間 - 控制 DOM 樣式 - 建立計時器重複執行函式 ## 基礎語法 ### JavaScript - [`Date` 物件](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Date) - [`getHours()`](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Date/getHours) - [`getMinutes()`](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Date/getMinutes) - [`getSeconds()`](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Date/getSeconds) ### BOM - [`setInterval`](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/setInterval) 計時器 ## 說明 ### 1. 將指針原始樣式改成 12 點鐘方向 課程提供的原始 CSS,在計算角度時,要補 90度,因此這邊會稍作修改。 ### 2. 計算角度 一個圓有 360 度: - 60 秒 - 360 / 60 = 6 - 每秒轉 6 度 - 60 分鐘 - 360 / 60 = 6 - 每分鐘轉 6 度 - 12 個小時 - 360 / 12 = 30 - 每一小時轉 30 度 ## 實作 ### 1. 步驟 #### Step 1  調整 CSS 在 `.clock-face` 新增一個中心點方便定位。 ```css .clock-face::after { content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); border-radius: 50%; background-color: white; width: 10px; height: 10px; } ``` 將原本的 `.hand` 改掉, ```css .hand { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } ``` 新增 `.hour-hand` `.min-hand` `.second-hand`: 我們將指針的樣式寫在偽元素,這樣旋轉容器時,就會以中心旋轉。 並且將指針起點改成 12 點鐘方向,這樣就不用額外計算多出來的角度。 ```css .hour-hand::after { position: absolute; content: ''; width: 10px; height: 100px; background-image: linear-gradient(black 50%, transparent 50% 100%); } .min-hand::after { position: absolute; content: ''; width: 10px; height: 200px; background-image: linear-gradient(black 50%, transparent 50% 100%); } .second-hand::after { position: absolute; content: ''; width: 4px; height: 160px; background-image: linear-gradient(black 50%, transparent 50% 100%); } ``` #### Step 2  取得指針的 DOM 物件 ```javascript const hour = document.querySelector('.hour-hand'); const min = document.querySelector('.min-hand'); const second = document.querySelector('.second-hand'); ``` #### Step 3 建立函式 `setClock()` ```javascript function setClock() { const now = new Date(); let hourDeg = now.getHours() * 30; let minDeg = now.getMinutes() * 6; let secondDeg = now.getSeconds() * 6; hour.style.transform = `rotate(${hourDeg}deg)`; min.style.transform = `rotate(${minDeg}deg)`; second.style.transform = `rotate(${secondDeg}deg)`; } ``` JavaScript 的 Date 物件只能以建構式的方式來產生,因此這裡用到 `new` 關鍵字,取得現在時間。 分別取得秒、分、時的時間,並計算角度,用來控制指針的旋轉度數。 #### Step 4 呼叫函式並加上計時器 ```javascript setClock(); // 初始化畫面 setInterval(setClock, 1000); ``` `setInterval` 計時器,可以設定每隔一段時間重複執行,這裡設 1 秒。 另外關於畫面顯示的計時器也可以使用 [`requestAnimationFrame`](https://developer.mozilla.org/zh-TW/docs/Web/API/Window.requestAnimationFrame),它會跟據硬體的效能來控制更新頻率,簡單來說就是會以你硬體能顯示最大 FPS 來刷新頻率。 目前已完成初步功能。 #### Step 5 微調 由於現實中指針不會是時間一到就直接跳到下一格,因此這裡的時針與分針還需要補上一些細節。 - 時針 - 每小時一格有 30 度 - 一小時有 60 分鐘 - 因此角度還要加上「目前幾分 \* (30 / 60)」 - 分針 - 每分鐘有 6 度 - 每分鐘有 60 秒 - 因此角度還要加上「目前幾秒 \* (6 / 60)」 稍作微調程式碼: ```javascript let secondDeg = now.getSeconds() * 6; let minDeg = now.getMinutes() * 6 + now.getSeconds() * (6 / 60); let hourDeg = now.getHours() * 30 + now.getMinutes() * (30 / 60); ``` #### Step END ```javascript (function() { const hour = document.querySelector('.hour-hand'); const min = document.querySelector('.min-hand'); const second = document.querySelector('.second-hand'); function setClock() { const now = new Date(); let secondDeg = now.getSeconds() * 6; let minDeg = now.getMinutes() * 6 + now.getSeconds() * (6 / 60); let hourDeg = now.getHours() * 30 + now.getMinutes() * (30 / 60); second.style.transform = `rotate(${secondDeg}deg)`; min.style.transform = `rotate(${minDeg}deg)`; hour.style.transform = `rotate(${hourDeg}deg)`; } setClock(); // 初始化畫面 setInterval(setClock, 1000); })(); ``` ### 2. 實作連結 - [初版](https://chupai.github.io/JS30/source_code/Day02/index1.html) - [美化](https://chupai.github.io/JS30/source_code/Day02/index.html)