第二天的目標是建置一個對應真實時間的時鐘
Github 檔案位置:02 - JS and CSS Clock
網頁一開始的樣子如下
可以先去看看 最後的成品
將程式的要求拆分步驟後,我們需要做的事情如下
首先,我們可以利用 const now = new Date();
函式獲取本地時間
Date 物件的詳細介紹在 MDN Web Docs - Date 這裡,裡面有詳細的使用方式
這次我們會用到的如下
now.getSeconds()
得到現在秒數now.getMinutes()
得到現在分鐘數now.getHours()
得到現在小時數首先,我們要先利用 CSS 效果 transform: rotate(90deg);
測試指針的旋轉狀況
以下先探討原作者及 Alex 老師在指針上的 CSS 撰寫方式
在原影片中將每個 .hand
直接畫為一個指針,再調整 CSS 屬性 top:50%
將指針往上移到中心以上
.hand {
width: 50%;
height: 6px;
background: black;
position: absolute;
top: 50%;
}
這樣做會在旋轉時延伸一個問題,如果直接以 transform: rotate(90deg);
旋轉,會是指針的中端旋轉,而不是以時鐘中心點那端為旋轉軸。
因此,我們可以使用 transform-origin: 100%;
更改旋轉軸位置為最頂點,也就是時鐘中心點
此做法是直接將 .hand 設為一塊大的方塊,指針採用偽元素的方式製作,這樣在操控指針的旋轉時,就可以直接旋轉中心點和時鐘一樣的方塊,達到指針正常旋轉的效果
.hand {
width: 100%;
height: 100%;
position: absolute;
transition: all 0.05s;
transition-timing-function: cubic-bezier(1, 1.15, 1, -0.43);
}
指針的偽元素寫法如下,主要是將指針的高設為方格的一半,再利用 transform: translate(-50%, 0%);
將指針拉高至末端停在圓中心,這樣就能達成在方格旋轉時指針能正常旋轉了。
.second-hand:after{
content: '';
display: block;
position: absolute;
height: 50%;
width: 4px;
background-color: black;
left: 50%;
bottom: 50%;
transform: translate(-50%, 0%);
}
其中會利用到的技術是 CSS 的 transform: rotate(deg)
屬性,我們將利用 JS 操控三個指針的旋轉
旋轉的方式就是選取指針元素後,以 secondHand.style.transform = rotate(deg)
的方式設定隨時間而變的 deg 值。
deg 值的轉換則是如下
const hourHand = document.querySelector('.hour-hand');
const minHand = document.querySelector('.min-hand');
const secondHand = document.querySelector('.second-hand');
function setClock(){
const now = new Date();
let secondDeg = now.getSeconds() * 6; // (360 / 60) = 6
let minDeg = now.getMinutes() * 6 + ((now.getSeconds() / 60) * 6); // (360 / 60) = 6
let hourDeg = now.getHours() * 30 + ((now.getMinutes() / 60) * 30); //(360 / 12) = 30
secondHand.style.transform = `rotate(${secondDeg}deg)`;
minHand.style.transform = `rotate(${minDeg}deg)`;
hourHand.style.transform = `rotate(${hourDeg}deg)`;
}
定時旋轉則可以使用三種計時器,沒有說誰好誰壞,但第三種 window.requestAnimationFrame()
的方式可以避免計時器的時間與 CSS 動畫持續時間不同。
function timeoutSetClock(){
setClock();
setTimeout(timeoutSetClock, 1000);
}
setTimeout(timeoutSetClock, 1000);`
setInterval(setClock, 1000);
function animationSetClock(){
setClock();
window.requestAnimationFrame(animationSetClock);
}
window.requestAnimationFrame(animationSetClock);
.clock-face {
position: relative;
width: 100%;
height: 100%;
transform: translateY(-3px); /* account for the height of the clock hands */
}
.clock-face:after{
content:'';
display: block;
width:25px;
height:25px;
border-radius: 100%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: white;
}
.hand {
width: 100%;
height: 100%;
position: absolute;
transition: all 0.05s;
transition-timing-function: cubic-bezier(1, 1.15, 1, -0.43);
}
.second-hand:after{
content: '';
display: block;
position: absolute;
height: 50%;
width: 4px;
background-color: black;
left: 50%;
bottom: 50%;
transform: translate(-50%, 0%);
}
.min-hand:after{
content: '';
display: block;
position: absolute;
height: 40%;
width: 7px;
background-color: black;
left: 50%;
bottom: 50%;
transform: translate(-50%, 0%);
}
.hour-hand:after{
content: '';
display: block;
position: absolute;
height: 30%;
width: 10px;
background-color: black;
left: 50%;
bottom: 50%;
transform: translate(-50%, 0%);
}
const hourHand = document.querySelector('.hour-hand');
const minHand = document.querySelector('.min-hand');
const secondHand = document.querySelector('.second-hand');
function setClock(){
const now = new Date();
let secondDeg = now.getSeconds() * 6; // (360 / 60) = 6
let minDeg = now.getMinutes() * 6 + ((now.getSeconds() / 60) * 6); // (360 / 60) = 6
let hourDeg = now.getHours() * 30 + ((now.getMinutes() / 60) * 30); //(360 / 12) = 30
secondHand.style.transform = `rotate(${secondDeg}deg)`;
minHand.style.transform = `rotate(${minDeg}deg)`;
hourHand.style.transform = `rotate(${hourDeg}deg)`;
}
function timeoutSetClock(){
setClock();
setTimeout(timeoutSetClock, 1000);
}
function animationSetClock(){
setClock();
window.requestAnimationFrame(animationSetClock);
}
setClock();
// setInterval(setClock, 1000);
// setTimeout(timeoutSetClock);
window.requestAnimationFrame(animationSetClock);
以上是第二天的製作紀錄,如有錯誤或不足的地方還請多多指教 >.<
CSS + JS Clock in Vanilla JS — #JavaScript30 2/30
[Alex 宅幹嘛] 深入淺出 Javascript30 快速導覽:Day 2:CSS + JS Clock