前言
实现一个功能齐全的时钟,具有动态指针、日期显示和主题切换功能。通过 JavaScript 的定时器和事件监听器,实现了时钟的实时更新和主题的平滑切换。
默认模式:
点击Dark mode按钮 ,即可切换成为深夜模式:
点击Light mode按钮,可转换回去。
实现一个带有主题切换功能的时钟。主要功能包括:
-
时钟显示:
- 显示当前时间(小时、分钟、秒)。
- 显示当前日期(星期几、月份、日期)。
- 通过三个指针(时针、分针、秒针)动态展示当前时间。
-
主题切换:
- 提供一个按钮,用于切换页面的主题(亮模式和暗模式)。
- 切换主题时,页面背景、文字颜色、指针颜色等都会相应变化。
-
动画效果:
- 指针的旋转动画,每秒更新一次,以确保时钟的准确性。
- 页面主题切换时的平滑过渡效果。
JavaScript 部分代码详细解析
1. 元素选择与变量定义
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')
- 通过
document.querySelector选择页面中的各个元素,并将其存储在变量中,以便后续操作。
2. 日期和时间数组
const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
- 定义了两个数组
days和months,分别存储星期几和月份的名称,用于显示日期信息。
3. 主题切换功能
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'
}
})
- 为
toggle按钮添加了一个点击事件监听器。 - 当按钮被点击时,检查
html元素是否包含dark类。- 如果包含,则移除
dark类,并将按钮文本改为 "Dark mode"。 - 如果不包含,则添加
dark类,并将按钮文本改为 "Light mode"。
- 如果包含,则移除
4. 设置时间函数
function setTime() {
const time = new Date();
const month = time.getMonth()
const day = time.getDay()
const date = time.getDate()
const hours = time.getHours()
const hoursForClock = hours >= 13 ? hours % 12 : hours;
const minutes = time.getMinutes()
const seconds = time.getSeconds()
const ampm = hours >= 12 ? 'PM' : 'AM'
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)`
timeEl.innerHTML = `${hoursForClock}:${minutes < 10 ? `0${minutes}` : minutes} ${ampm}`
dateEl.innerHTML = `${days[day]}, ${months[month]} <span class="circle">${date}</span>`
}
setTime函数用于更新时钟的显示。- 获取当前时间,并计算出小时、分钟、秒的具体值。
- 根据当前时间计算出指针的旋转角度,并应用到对应的指针元素上。
- 更新
timeEl和dateEl的内容,显示当前时间和日期。
5. 数值映射函数
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;
}
scale函数用于将一个范围内的数值映射到另一个范围内。- 例如,将小时数(0-12)映射到角度(0-360),以便计算指针的旋转角度。
6. 初始化和定时更新
setTime()
setInterval(setTime, 1000)
- 调用
setTime函数初始化时钟显示。 - 使用
setInterval每秒调用一次setTime函数,以确保时钟的实时更新。
总结
这段代码实现了一个功能齐全的时钟,具有动态指针、日期显示和主题切换功能。通过 JavaScript 的定时器和事件监听器,实现了时钟的实时更新和主题的平滑切换。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Theme-clock</title>
</head>
<body>
<!-- Inspired by this dribbble shot https://dribbble.com/shots/5958443-Alarm-clock -->
<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>
</body>
<style>
@import url('https://fonts.googleapis.com/css?family=Heebo:300&display=swap');
* {
box-sizing: border-box;
}
:root {
--primary-color: #000;
--secondary-color: #fff;
}
html {
transition: all 0.5s ease-in;
}
html.dark {
--primary-color: #fff;
--secondary-color: #333;
}
html.dark {
background-color: #111;
color: var(--primary-color);
}
body {
font-family: 'Heebo', sans-serif;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
overflow: hidden;
margin: 0;
}
.toggle {
cursor: pointer;
background-color: var(--primary-color);
color: var(--secondary-color);
border: 0;
border-radius: 4px;
padding: 8px 12px;
position: absolute;
top: 100px;
}
.toggle:focus {
outline: none;
}
.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 linear;
}
.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%;
}
.time {
font-size: 60px;
}
.date {
color: #aaa;
font-size: 14px;
letter-spacing: 0.3px;
text-transform: uppercase;
}
.date .circle {
background-color: var(--primary-color);
color: var(--secondary-color);
border-radius: 50%;
height: 18px;
width: 18px;
display: inline-flex;
align-items: center;
justify-content: center;
line-height: 18px;
transition: all 0.5s ease-in;
font-size: 12px;
}
</style>
<script>
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", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
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'
}
})
function setTime() {
const time = new Date();
const month = time.getMonth()
const day = time.getDay()
const date = time.getDate()
const hours = time.getHours()
const hoursForClock = hours >= 13 ? hours % 12 : hours;
const minutes = time.getMinutes()
const seconds = time.getSeconds()
const ampm = hours >= 12 ? 'PM' : 'AM'
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)`
timeEl.innerHTML = `${hoursForClock}:${minutes < 10 ? `0${minutes}` : minutes} ${ampm}`
dateEl.innerHTML = `${days[day]}, ${months[month]} <span class="circle">${date}</span>`
}
// StackOverflow https://stackoverflow.com/questions/10756313/javascript-jquery-map-a-range-of-numbers-to-another-range-of-numbers
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;
}
setTime()
setInterval(setTime, 1000)
</script>
</html>