第15章 DOM进阶与定时器

七段数码管计时器:竞赛3分题 | 课型:实习课 | 建议课时:3节

🏠 返回总目录 / 第15章

🎯 学习目标

知识目标

  • 掌握setInterval/clearInterval定时器
  • 掌握用className切换实现视觉变化
  • 掌握数字进位算法
  • 了解防抖与节流

能力目标

  • 能独立完成竞赛任务6"七段数字计时器"
  • 能用定时器驱动界面持续更新
  • 能排查定时器叠加泄漏问题

德育目标

  • 培养算法思维与严谨逻辑
  • 通过3分难题磨炼攻坚意志

教学重点

  • setInterval的启动与清除
  • 七段数码管的"灭段"设计
  • 五位数字的进位链

教学难点

  • 进位条件:99.99秒归零
  • 先clearInterval再启动防叠加

💻 实例演示1个实例 · 可在线运行

▶ 竞赛任务6:七段数字计时器

00:00格式五位七段数码管,启动/停止/复位三按钮,10ms精度——2026纯JS版。

新窗口运行 下载源码

操作步骤

  1. 打开demo1.html,点击"启动计时器"观察数字跳动
  2. 观察最右侧位变化最快——理解进位方向
  3. 连续点击两次"启动",思考为什么要先clearInterval
  4. 点击停止、复位验证三按钮
  5. 用开发者工具观察display类名如何从display-0变到display-9
  6. 对照评分点:尺寸/颜色/三按钮/进位/归零

效果观察点

  • className整体替换实现数字切换
  • 灭段用opacity:.15模拟数码管暗段
  • tick中while循环完成连续进位
查看核心代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Task 6 - 七段计时器</title>
<style>
  * { margin: 0; padding: 0; }
  body { background: #29303b; min-height: 100vh; display: flex; flex-direction: column;
         align-items: center; justify-content: center; font-family: Arial, sans-serif; }
  .wrapper { display: flex; align-items: center; }
  .display { width: 90px; height: 175px; position: relative; margin: 9px; }
  .x { width: 60px; border: 4.5px solid rgb(220, 75, 82); border-radius: 10px; position: absolute; }
  .y { height: 60px; border: 4.5px solid rgb(220, 75, 82); border-radius: 10px; position: absolute; }
  .a { left: 25%; top: 4%; } .b { left: 45%; top: 16%; } .c { left: 45%; top: 38%; }
  .d { left: 25%; top: 50%; } .e { left: 5%; top: 38%; } .f { left: 5%; top: 16%; } .g { left: 25%; top: 27%; }
  .display-0 .g { opacity: .15; }
  .display-1 .a, .display-1 .d, .display-1 .e, .display-1 .f, .display-1 .g { opacity: .15; }
  .display-2 .f, .display-2 .c { opacity: .15; }
  .display-3 .e, .display-3 .f { opacity: .15; }
  .display-4 .a, .display-4 .d, .display-4 .e { opacity: .15; }
  .display-5 .b, .display-5 .e { opacity: .15; }
  .display-6 .b { opacity: .15; }
  .display-7 .d, .display-7 .e, .display-7 .f, .display-7 .g { opacity: .15; }
  .display-9 .e { opacity: .15; }
  .colon { width: 10px; height: 60px; margin: 0 4px; position: relative; }
  .colon::before, .colon::after { content: ''; position: absolute; left: 0; width: 10px; height: 10px;
      border-radius: 50%; background: rgb(220, 75, 82); }
  .colon::before { top: 0; } .colon::after { bottom: 0; }
  button { margin: 24px 6px 0; padding: 10px 22px; font-size: 15px; border: none; border-radius: 8px;
           background: #38d6c4; color: #123a52; cursor: pointer; font-weight: bold; }
  button:hover { background: #c77728; color: #fff; }
</style>
</head>
<body>
  <div class="wrapper" id="wrapper"></div>
  <div>
    <button id="btnStart">启动计时器</button>
    <button id="btnStop">停止计时器</button>
    <button id="btnReset">复位计时器</button>
  </div>
<script>
  // 生成五个数码管 + 冒号:格式 00:00.0(厘秒) 简化为 000:00
  const wrapper = document.getElementById('wrapper');
  const segs = '<div class="a x"></div><div class="b y"></div><div class="c y"></div>' +
               '<div class="d x"></div><div class="e y"></div><div class="f y"></div><div class="g x"></div>';
  for (let i = 0; i < 5; i++) {
    if (i === 3) { const c = document.createElement('div'); c.className = 'colon'; wrapper.appendChild(c); }
    const d = document.createElement('div');
    d.className = 'display display-0'; d.innerHTML = segs; wrapper.appendChild(d);
  }
  const displays = [...wrapper.querySelectorAll('.display')];
  // digits = [十秒, 个秒, 十厘秒, 厘秒, 毫秒位] 简化:00:00 格式为 [秒十,秒个,厘十,厘个] + 第五位
  let digits = [0, 0, 0, 0, 0];
  let timer = null;
  function render() {
    digits.forEach((n, i) => { displays[i].className = 'display display-' + n; });
  }
  function tick() {
    let i = digits.length - 1;
    digits[i]++;
    while (i > 0 && digits[i] > 9) { digits[i] = 0; digits[--i]++; }
    if (digits[0] > 9) digits = [0, 0, 0, 0, 0]; // 99999归零
    render();
  }
  document.getElementById('btnStart').addEventListener('click', () => {
    clearInterval(timer);              // 防叠加:先清除
    timer = setInterval(tick, 10);
  });
  document.getElementById('btnStop').addEventListener('click', () => clearInterval(timer));
  document.getElementById('btnReset').addEventListener('click', () => {
    clearInterval(timer); digits = [0, 0, 0, 0, 0]; render();
  });
</script>
</body>
</html>

📋 实习任务书

任务目标:独立完成竞赛任务6七段计时器

任务内容与评分
任务1:画出七段位置草图并标注a-g(15分)
任务2:完成数码管CSS与display-0~9灭段表(25分)
任务3:实现tick进位算法(25分)
任务4:实现启动/停止/复位三按钮(20分)
任务5:写出防定时器叠加的正确做法(15分)

自我评价

📚 课后作业与预习