【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 里的秒针一样,优雅前行。

相关推荐
AlienZHOU5 小时前
AI Coding 时代下,我的技术面试实践分享
前端·后端·面试
Captaincc9 小时前
AI用量v0.1.11更新发布 新增 jusage doctor 诊断指令 托盘展示token 和余额 新增 AutoClaw 支持
前端·后端·vibecoding
计算机魔术师10 小时前
德国Wiki被黑后两周,OpenAI终于把模型失控的账本摊开了
前端
kyriewen10 小时前
我让 AI 当面试官面了我一轮:第 3 个追问我就卡住了(附 10 道追问清单)
前端·面试·ai编程
IT_陈寒11 小时前
Python的GIL把我坑惨了,多线程跑得比单线程还慢
前端·人工智能·后端
前端snow11 小时前
ai agent --- 多agent框架之图编排引擎-langgraph
前端
竹林81811 小时前
OmniPic Studio v3.2.1 核心技术架构与全平台发版解析文档
前端·浏览器
JamesZhang8007811 小时前
页面内存只涨不跌? 一次泄漏排查, 牵出 WeakMap 的诞生
前端
Z小明11 小时前
第 6 章 组件进阶
前端·vue.js
江华森11 小时前
HTTP请求的完整过程详解:从DNS解析到TCP挥手的微秒级实战分析
前端