這次作品的靈感是來自這個dribbble
CodePen:
https://codepen.io/zyrxdkoz/pen/dyRWKZM
clock部分
色彩模式切換
讓我們來看程式碼(值得特別注意的地方會加上備註):
Html部分
<!DOCTYPE html>
// 會在html加上dark選擇器
<html lang="en">
<head>
// 略
</head>
<body>
<button class="toggle">Dark mode</button>
<div class="clock-container">
// 就跟真正的時鐘一樣有不同的元件。
<div class="clock">
<div class="needle hour"></div>
<div class="needle minute"></div>
<div class="needle second"></div>
<div class="center-point"></div>
</div>
<div class="time"></div>
<div class="date"></div>
</div>
<script src="script.js"></script>
</body>
</html>
CSS部分
(節錄部分)
:root {
--primary-color: #000;
--secondary-color: #fff;
}
html {
transition: all 0.5s ease-in;
}
html.dark {
--primary-color: #fff;
--secondary-color: #333;
background-color: #111;
color: var(--primary-color);
}
.clock-container {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
}
.clock {
position: relative;
width: 200px;
height: 200px;
}
.needle {
background-color: var(--primary-color);
position: absolute;
top: 50%;
left: 50%;
height: 65px;
width: 3px;
// 設定元素變化的原點:底部中間位置
transform-origin: bottom center;
transition: all 0.5s ease-in;
}
// 運用trasform屬性控制指針的定位和旋轉行為
.needle.hour {
transform: translate(-50%, -100%) rotate(0deg);
}
.needle.minute {
transform: translate(-50%, -100%) rotate(0deg);
height: 100px;
}
.needle.second {
transform: translate(-50%, -100%) rotate(0deg);
height: 100px;
background-color: #e74c3c;
}
// 指針中心
.center-point {
background-color: #e74c3c;
width: 10px;
height: 10px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
}
// 用偽元素做出時鐘的中心部件(會依照色彩模式變換顏色)
.center-point::after {
content: '';
background-color: var(--primary-color);
width: 5px;
height: 5px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
}
Javascript部分
const hourEl = document.querySelector('.hour')
const minuteEl = document.querySelector('.minute')
const secondEl = document.querySelector('.second')
const timeEl = document.querySelector('.time')
const dateEl = document.querySelector('.date')
const toggle = document.querySelector('.toggle')
const days = [
'Sunday',
// 略
]
const months = [
'Jan',
// 略
'Dec',
]
// 白天/夜晚模式切換,單純用classList的remove、add來實現
toggle.addEventListener('click', (e) => {
const html = document.querySelector('html')
if (html.classList.contains('dark')) {
html.classList.remove('dark')
e.target.innerHTML = 'Dark mode'
} else {
html.classList.add('dark')
e.target.innerHTML = 'Light mode'
}
})
// 這個函式可以在一個範圍內劃定要跑的階數。
const scale = (num, in_min, in_max, out_min, out_max) => {
return ((num - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min
}
function setTime() {
// 用new運算子建立一個Date物件,
const time = new Date()
const month = time.getMonth()
const day = time.getDay()
const date = time.getDate()
const hours = time.getHours()
// 讓小時單位為12小時制
const hoursForClock = hours >= 13 ? hours % 12 : hours
const minutes = time.getMinutes()
const seconds = time.getSeconds()
// 顯示PM或AM
const ampm = hours >= 12 ? 'PM' : 'AM'
// 以下時針、分針、秒針都帶入scale函式來rotate。
hourEl.style.transform = `translate(-50%, -100%) rotate(${scale(
hoursForClock, // 參考的數值
0, // 參考數值的變化範圍(最小)
12, // 參考數值的變化範圍(最大)
0, // 輸出數值的變化範圍(最小)
360 // 輸出數值的變化範圍(最大)
)}deg)`
minuteEl.style.transform = `translate(-50%, -100%) rotate(${scale(
minutes,
0,
60,
0,
360
)}deg)`
secondEl.style.transform = `translate(-50%, -100%) rotate(${scale(
seconds,
0,
60,
0,
360
)}deg)`
// 讓分鐘單位的顯示為十進位,1 => 01
timeEl.innerHTML = `${hoursForClock}:${
minutes < 10 ? `0${minutes}` : minutes
} ${ampm}`
dateEl.innerHTML = `${days[day]}, ${months[month]} <span class="circle">${date}</span>`
}
setTime()
// 每一秒鐘執行一次setTime函式,啟動時鐘。
setInterval(setTime, 1000)