【html】canvas实现一个时钟

前言

"一行代码能做什么?"------有人用一行代码写出圣诞树,有人用一行代码写出 3D 隧道。

今天我想带你回到最原始的画布:HTML5 Canvas。

我们只用 一个 <canvas> 标签 + 一份被注释到"膨胀"的源码 ,做一只实时跳动的机械时钟

读完你不仅能照抄代码,还能彻底搞懂:

  1. 为什么 requestAnimationFramesetInterval 更适合动画
  2. 三角函数在前端到底怎么用
  3. 如何把"时间"映射成"角度"再映射成"坐标"

在线预览

把下面 60 行"真身"粘进任意 .html 文件,双击即可运行:

(我已经把注释写成了"伪 600 行"------每行都带中文讲解,复制即食)

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>Canvas Clock | 注释版</title>
  <style>
    /* 让时钟水平居中,再给个浅灰背景+深色边框,高级感拉满 */
    canvas {
      display: block;
      margin: 50px auto;
      background: #f4f4f4;
      border: 2px solid #333;
      border-radius: 50%; /* 圆表盘当然要圆角 */
      box-shadow: 0 0 20px rgba(0,0,0,.15);
    }
  </style>
</head>
<body>
  <!-- 600×600 像素的画布,id 叫"clock",后面 JS 就靠它画画 -->
  <canvas id="clock" width="600" height="600"></canvas>

  <script>
    /* 主绘制函数:每帧擦掉旧画面 -> 重新画新画面,形成动画 */
    function drawClock() {
      const canvas = document.getElementById('clock');
      const ctx    = canvas.getContext('2d');      // 拿到 2D 画笔
      const cx = 300, cy = 300, r = 250;           // 圆心(cx,cy) 半径 r

      /* 1. 清屏:把上一帧的画面整个擦掉,避免拖影 */
      ctx.clearRect(0, 0, 600, 600);

      /* 2. 表盘:一个灰色大圆 */
      ctx.beginPath();
      ctx.arc(cx, cy, r, 0, Math.PI * 2);
      ctx.fillStyle = '#ccc';
      ctx.fill();

      /* 3. 拿到当前时分秒 */
      const now = new Date();
      const h = now.getHours();
      const m = now.getMinutes();
      const s = now.getSeconds();

      /* 4. 角度换算:把"时间"转成"顺时针角度",再减去 90° 让 0° 指向 12 点 */
      const hAngle = ((h % 12) + m / 60) * 30  - 90;  // 每小时 30°
      const mAngle = (m + s / 60)        * 6   - 90;  // 每分钟 6°
      const sAngle = s                   * 6   - 90;  // 每秒 6°

      /* 5. 画三根指针:颜色、长度、线宽各不相同,秒针用骚红色 */
      drawHand(ctx, hAngle, 100, 12, '#333');         // 时针
      drawHand(ctx, mAngle, 150, 8,  '#555');         // 分针
      drawHand(ctx, sAngle, 180, 3,  '#e74c3c');      // 秒针

      /* 6. 中心小圆点:盖住三根指针的尾巴,显得更像实物 */
      ctx.beginPath();
      ctx.arc(cx, cy, 10, 0, Math.PI * 2);
      ctx.fillStyle = '#333';
      ctx.fill();

      /* 7. 请求下一帧:浏览器会在下一次重绘前再调 drawClock(),形成无限循环 */
      requestAnimationFrame(drawClock);
    }

    /* 工具函数:画一根指针
       angle:旋转角度(度)  length:长度   width:线宽   color:颜色 */
    function drawHand(ctx, angle, length, width, color) {
      const rad = (angle * Math.PI) / 180;   // 角度转弧度
      const x = 300 + Math.cos(rad) * length;
      const y = 300 + Math.sin(rad) * length;

      ctx.beginPath();
      ctx.moveTo(300, 300);
      ctx.lineTo(x, y);
      ctx.lineWidth = width;
      ctx.strokeStyle = color;
      ctx.lineCap = 'round';   // 圆角线帽,更柔和
      ctx.stroke();
    }

    /* 启动!第一次手动调用,后面就靠 requestAnimationFrame 自动循环 */
    drawClock();
  </script>
</body>
</html>

关键知识点拆解

步骤 前端技巧 一句话记忆
清屏 ctx.clearRect 动画第一定律:先擦后画
角度 -90° 修正 数学 0° 指向 3 点,时钟 0° 指向 12 点
弧度 Math.PI / 180 角度给人类看,弧度给三角函数看
指针终点 cos 管 x,sin 管 y 高中三角函数终于还给了体育老师
动画节流 requestAnimationFrame 浏览器帮你匹配屏幕刷新率,60 fps 不丢帧

还能怎么玩?

  1. 换皮肤:把表盘改成深色霓虹,秒针加 glow 阴影,瞬间赛博朋克。
  2. 加刻度 :用 for 循环画 60 个小圆点,12 个粗点代表小时。
  3. 加数字ctx.fillText 把 1~12 画到对应位置,注意同样要转角度。
  4. 响应式 :把 600 改成 min(window.innerWidth, window.innerHeight),再动态算圆心。
  5. 音效:每秒播放一次"滴答"采样,Web Audio API 只要 5 行。

结语

Canvas 像一张永远干不掉的水彩纸:

你可以在上面画像素、画粒子、画星空,也可以画一只最朴素的时钟。
"会动"的不只是指针,还有你对前端世界的好奇心。

把这份代码存进收藏夹,下次面试被问到"如何实现平滑动画"时,

requestAnimationFrame + 三角函数 这套组合拳打出来,

面试官大概率会点点头:嗯,基础很扎实。


源码仓库

GitHub 完整仓库

👉 gitter.com/koreation/canvas-clock 欢迎 Star & PR!


如果这篇文章帮到你,记得点个赞,
让你的时间,也像 Canvas 里的秒针一样,优雅前行。

相关推荐
举个栗子dhy1 分钟前
第一章、React + TypeScript + Webpack项目构建
前端·javascript·react.js
大杯咖啡5 分钟前
localStorage与sessionStorage的区别
前端·javascript
RaidenLiu17 分钟前
告别陷阱:精通Flutter Signals的生命周期、高级API与调试之道
前端·flutter·前端框架
非凡ghost17 分钟前
HWiNFO(专业系统信息检测工具)
前端·javascript·后端
非凡ghost19 分钟前
FireAlpaca(免费数字绘图软件)
前端·javascript·后端
非凡ghost26 分钟前
Sucrose Wallpaper Engine(动态壁纸管理工具)
前端·javascript·后端
拉不动的猪27 分钟前
为什么不建议项目里用延时器作为规定时间内的业务操作
前端·javascript·vue.js
该用户已不存在34 分钟前
Gemini CLI 扩展,把Nano Banana 搬到终端
前端·后端·ai编程
地方地方36 分钟前
前端踩坑记:解决图片与 Div 换行间隙的隐藏元凶
前端·javascript
小猫由里香41 分钟前
小程序打开文件(文件流、地址链接)封装
前端