功能
製作一個實時的時鐘
step 1 : 設置時針、分針、秒針的 CSS 樣式
.hand {
width: 50%;
height: 6px;
background: black;
position: absolute;
top: 50%;
// 改變軸心點 transform-origin:x,y,設為 100% 後(或用 right),讓指針的軸心改在最右邊
transform-origin: 100%;
// 旋轉元素,正值為順時針旋轉,負值為逆時針旋轉
transform: rotate(90deg);
transition: all 0.05s linear;
// 指針末端修尖
border-radius: 30% 0 0 30%;
}
.hour-hand {
height: 10px;
margin-top: -5px;
transform-origin: 100%;
transition: all 1s linear;
}
.second-hand {
background-color: red;
// 調整動畫轉場效果貝茲曲線:cubic-bezier
transition: all 0.05s cubic-bezier(0.25, 0.1, 0.84, 2.82);
}
step 2 :JS 取得當前時間,以及與時鐘上對應的角度
- 分針、秒針每一格走的角度: 360 度 / 60(分、秒) = 6 度
- 時針每一格走的角度: 360 度 / 12(小時) = 30 度
細節處理: 由於時針與分針會因為時間的推移,慢慢前往下一格,不是一次就跳到下一格,所以把這個也考慮進去後角度才精準
- 秒針角度: (當前秒數 / 60 秒)* 360 度
- 分針角度: (當前分鐘 / 60 分) 360 度 + (當前秒數 / 60 秒) 6 (每格 6 度)
- 時針角度: (當前小時 / 12 小時) 360 度 + (當前分鐘 / 60 分) 30 (每格 30 度)
function setClock(){
let now = new Date()
let second = now.getSeconds()
let secondDegrees = ((second / 60) * 360) + 90
secondHand.style.transform = `rotate(${secondDegrees}deg)`
let minute = now.getMinutes()
let minusDegrees = (minute / 60) * 360 + (minute / 60) * 6 + 90
minuteHand.style.transform = `rotate(${minusDegrees}deg)`
let hour = now.getHours()
let hoursDegrees = (hour / 12) * 360 + (hour/ 60) * 30 + 90
hourHand.style.transform = `rotate(${hoursDegrees}deg) scaleX(0.7)`
}
}
step 3 :JS 設定定時器,每秒重複執行一次
// 用 setInterval 方法,設定固定間隔,重複執行一次
setInterval(setClock, 1000);
// 用 setTimeout 方法,設定多少時間後,執行一次,想要持續執行的話,要在 function 裡再 setTimeout 呼叫自己
// function handleTimeout() {
// setClock();
// setTimeout(handleTimeout, 1000);
// }
// setTimeout(handleTimeout, 1000);
// 用 window.requestAnimationFrame 方法,畫面更新,跟 setTimeout 一樣,要重複執行的話需在 function 裡呼叫自己
// function handleTimeAnimation() {
// setClock();
// window.requestAnimationFrame(handleTimeAnimation)
// }
// window.requestAnimationFrame(handleTimeAnimation);
Javascript
1. 用 element.style.<styleAttribute>
改變 CSS 效果:
const hourHand = document.querySelector('.hour-hand');
hourHand.style.transform = `rotate(${hoursDegrees}deg) scaleX(0.7)`;
2. setInterval、setTimeout、window.requestAnimationFrame 的區別
- setInterval(): 固定一段時間,重複執行 function(例如:時鐘、輪播)
// 第一個參數是要執行的 function,第二個參數固定多久時間(毫秒)執行
setInterval(callback, time)
- setTimeout():設定延遲時間,只執行一次
// 第一個參數是要執行的 function,第二個參數延遲的多長時間(毫秒)後執行
setInterval(callback, time)
- window.requestAnimationFrame():
處理畫面的更新,類似setTimeout()
只會執行一次,重複執行時要在 function 內呼叫自己,如果用 canvas 動畫,為了處理畫面流暢度,建議可使用window.requestAnimationFrame
// 第一個參數是要執行的 function,第二個參數延遲的多長時間(毫秒)後執行
window.requestAnimationFrame(callback)
延伸
秒針回到 0 秒時會閃一下,參考 Reference 提供的解決方法
當將指針為 90 度時,將 transition 屬性移除
if (secondDegrees === 90) secondHand.style.transition = 'all 0s'
else secondHand.style.transition = 'all 0.05s';
if (minusDegrees === 90) minuteHand.style.transition = 'all 0s'
else minuteHand.style.transition = 'all 0.1s'
參考資料:
- We build a CSS + JS Clock in Vanilla JS — #JavaScript30 2/30 @Wes Bos
- [Alex 宅幹嘛] 👨💻 深入淺出 Javascript30 快速導覽:Day 2:CSS + JS Clock @Alex 宅幹嘛
- 02 - JS and CSS Clock @guahsu
- 02 纯 JS、CSS 时钟 中文指南@soyaine
- [JS30] Day02: JS and CSS Clock@PJCHENder
- JS30 Day2 - JS and CSS Clock@Six
- JavaScript 30 — Day 2@Chloe Lo