JavaScript Canvas 实现昼夜切换时钟模拟器
作者:窗边听雨时间:2026-10-24 05:09:29浏览:337
本文介绍基于 JavaScript Canvas 实现的时钟模拟器,支持实时显示当前时间及白天/夜晚模式切换。文章解析了小时修正、状态恢复等核心代码逻辑,并展示完整 HTML/CSS/JS 实现方案,帮助开发者掌握 Canvas 绘图与交互技巧。
Canvas 时钟模拟器概述
这是一个 Canvas 时钟模拟器的示例,供参考学习。
主要功能介绍
该模拟器具备实时显示当前时间的功能,并支持在白天模式与夜晚模式之间进行切换。
核心代码逻辑解析
核心代码逻辑分析
代码中通过 `h = h > 12 ? h : h - 12` 实现下午时间的修正逻辑。
当画布状态出现混乱时,建议多使用 `ctx.restore()` 恢复到初始状态,而非强行通过反向操作(如先顺时针旋转 n 度再逆时针转回)来矫正状态。
参考代码实现
完整代码实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>钟表模拟器</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<canvas id="demo" width="1000px" height="600px">
您的浏览器不支持canvas,请升级您的浏览器
</canvas>
<div class="mode">
Night mode
</div>
<div id="fullscreen"></div>
</body>
<script>
/*
*
* 模拟钟表
*
* */
window.onload = () => {
// 浏览器禁止在你刚刚进入一个页面的时候就变成全屏,这是为了用户的安全和体验
// let elem = document.querySelector('#fullscreen')
//
// let event = new Event('myEvent')
//
// elem.addEventListener('myEvent', function (e) {
// console.log('ok')
// setTimeout(() => {
// let element = document.documentElement
// if (element.requestFullscreen) {
// element.requestFullscreen()
// } else if (element.msRequestFullscreen) {
// element.msRequestFullscreen()
// } else if (element.mozRequestFullScreen) {
// element.mozRequestFullScreen()
// } else if (element.webkitRequestFullscreen) {
// element.webkitRequestFullscreen()
// }
// }, 1000)
//
// }, false)
//
// elem.dispatchEvent(event)
// 切换夜晚模式和白天模式
let mode = document.getElementsByClassName('mode')
let nightMode = false
mode[0].onclick = () => {
nightMode = !nightMode
document.body.style.backgroundColor = nightMode === false ? '#fff' : '#000'
mode[0].innerHTML = nightMode === false ? 'Night mode' : 'exit'
if (nightMode) {
mode[0].style.color = '#000'
mode[0].style.backgroundColor = '#fff'
} else {
mode[0].style.color = '#fff'
mode[0].style.backgroundColor = '#000'
}
}
// 鼠标进入变色(可进一步简洁)
mode[0].onmouseover = () => {
if (nightMode) {
mode[0].style.color = '#000'
mode[0].style.backgroundColor = '#fff'
} else {
mode[0].style.color = '#fff'
mode[0].style.backgroundColor = '#000'
}
}
// 鼠标移出变色(可进一步简洁)
mode[0].onmouseout = () => {
if (nightMode) {
mode[0].style.color = '#fff'
mode[0].style.backgroundColor = '#000'
} else {
mode[0].style.color = '#000'
mode[0].style.backgroundColor = '#fff'
}
}
doHidden()
//
// 在一秒之后把光标去掉
function doHidden() {
let time = ''
document.body.onmousemove = () => {
document.body.style.cursor = 'default' // 恢复普通的光标
console.log('ok')
if (time) {
clearTimeout(time)
}
// 一秒后鼠标不动自动使光标消失
time = setTimeout(() => {
console.log('ok2')
document.body.style.cursor = nightMode === false ? `url('./imgs/hidden-box2.ani'), default` : `url('./imgs/hidden-box.ani'), default` // 这里的光标文件自己定义,最好是透明的空文件,找网上的图标文件转换器转换为ani文件
}, 1000)
}
}
let canvas = document.getElementById('demo')
let ctx = canvas.getContext('2d')
// 为了绘制时针,把坐标轴原点转移到画布中心
ctx.translate(500, 300)
// 开始正式绘制第一次
drew()
// 持续更新画布
setInterval(() => {
drew()
}, 500)
// 核心方法
function drew() {
// 刷新画布
ctx.fillStyle = nightMode === false ? '#fff' : '#000'
ctx.fillRect(-500, -300, 1000, 600)
// 时钟的大框框
ctx.save()
ctx.lineWidth = 6
ctx.strokeStyle = '#FFD034'
ctx.lineCap = 'round' // 笔画尖端为圆形
ctx.rotate(-90 * Math.PI / 180) // 十二点钟方向
ctx.beginPath()
ctx.arc(0, 0, 240, 0, 360 * Math.PI / 180)
ctx.stroke()
// 时针的刻度
ctx.save()
ctx.lineWidth = 10
ctx.strokeStyle = nightMode === true ? '#fff' : '#000'
for (let i = 0; i <= 11; i++) {
ctx.beginPath()
ctx.moveTo(200, 0)
ctx.lineTo(222, 0)
ctx.stroke()
ctx.rotate(30 * Math.PI / 180)
}
ctx.restore()
// 分针的刻度
ctx.save()
ctx.lineWidth = 4
ctx.strokeStyle = '#9B71EA'
for (let i = 0; i < 60; i++) {
if (i % 5 === 0) {
ctx.rotate(6 * Math.PI / 180)
} else {
ctx.beginPath()
ctx.moveTo(205, 0)
ctx.lineTo(222, 0)
ctx.stroke()
ctx.rotate(6 * Math.PI / 180)
}
}
ctx.restore()
// 获取时间,正式开始绘制
let date = new Date()
let s = date.getSeconds()
let m = date.getMinutes() + s / 60
let h = date.getHours() + m / 60
h = h > 12 ? h : h - 12 // 下午时间修正
// 画时针
ctx.save()
ctx.lineWidth = 18
ctx.strokeStyle = '#91FF99'
ctx.rotate(30 * h * Math.PI / 180) // 顺时针旋转的
ctx.beginPath()
ctx.moveTo(-20, 0)
ctx.lineTo(100, 0)
ctx.stroke()
ctx.restore()
// 画分针
ctx.save()
ctx.lineWidth = 12
ctx.strokeStyle = '#D291FF'
ctx.rotate(6 * m * Math.PI / 180) // 顺时针旋转的
ctx.beginPath()
ctx.moveTo(-35, 0)
ctx.lineTo(138, 0)
ctx.stroke()
ctx.restore()
// 画秒针
ctx.save()
ctx.lineWidth = 8
ctx.strokeStyle = '#FF8465'
ctx.rotate(6 * s * Math.PI / 180) // 顺时针旋转的
ctx.beginPath()
ctx.moveTo(-55, 0)
ctx.lineTo(115, 0)
ctx.stroke()
// 给秒针添加花样
ctx.beginPath()
ctx.arc(130, 0, 15, 0, 360 * Math.PI / 180)
ctx.stroke()
ctx.beginPath()
ctx.moveTo(145, 0)
ctx.lineTo(178, 0)
ctx.stroke()
// 最后给钟添加最中心的一个`固定器`
ctx.beginPath()
ctx.arc(0, 0, 15, 0, 360 * Math.PI / 180)
ctx.fillStyle = '#FF8465'
ctx.fill()
ctx.restore()
ctx.restore() // 回到最初最初最初的状态(主要是把为了画时针而把画布旋转的角度矫正回去)
}
}
</script>
<style>
* {
margin: 0;
padding: 0;
}
body {
background-color: #fff;
text-align: center;
transition: 0.5s;
}
#demo {
margin-top: 140px;
background-color: white;
border-radius: 15px;
}
.mode {
font-family: Consolas, serif;
width: 150px;
margin: 25px auto;
padding: 15px 25px;
border: 2px solid #CCCCCC;
border-radius: 15px;
background-color: white;
user-select: none;
box-shadow: 1px 1px 2px #aaaaaa;
transition: 0.5s;
cursor: pointer;
}
</style>
</html>
显示效果与模式切换
运行效果展示如下。
白天模式下的显示效果。

夜晚模式下的显示效果。

模式切换功能的演示。

开发总结
总结与心得
实际上,没有代码无法实现的效果,只有未被想到的创意。许多复杂的功能本质上是简单元素的整合,只要深入钻研,必然会有所收获。
以上就是本文的全部内容,希望能为各位的学习提供帮助,也欢迎大家继续支持本站。
作者最新文章
anime.js 快速入门:怎么引入库并编写第一个 DOM 动画
2026-11-05 14:22:43
在线JS解密后变量名仍乱码?结合浏览器DevTools调试还原
2026-11-04 20:26:01
怎么在浏览器中运行JavaScript代码并查看输出结果
2026-11-04 09:07:33
JS 获取屏幕分辨率:window.screen.width 与 height 用法
2026-11-04 08:52:48
为什么推荐用DOMContentLoaded代替window.onload初始化JS
2026-11-04 08:42:33
