第22章 让代码更专业:模块化与协作

从能跑到好维护 | 课型:理实一体课 | 建议课时:2节

🏠 返回总目录 / 第22章

🎯 学习目标

知识目标

  • 掌握代码注释规范与函数模块化
  • 掌握ES模块export/import
  • 掌握Git基础:init/add/commit/log
  • 了解npm与前端工程化生态

能力目标

  • 能把计时器JS拆分为多个模块
  • 能用Git管理代码版本与回滚
  • 能编写规范的README

德育目标

  • 培养协作意识与代码责任感
  • 理解开源精神与知识共享

教学重点

  • 单一职责的函数拆分
  • ES模块语法
  • Git四命令工作流

教学难点

  • 模块间的依赖关系梳理
  • Git回滚与冲突解决

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

▶ Git命令演练场

模拟终端:输入Git命令,可视化看到仓库状态变化。

新窗口运行 下载源码

操作步骤

  1. 打开demo1.html,依次输入git init
  2. 输入git add index.html,观察文件移到暂存区
  3. 输入git add . 暂存全部
  4. 输入git commit -m "first commit"观察仓库变化
  5. 输入git log查看提交历史
  6. 思考:工作区/暂存区/仓库三区的作用

效果观察点

  • 三区模型可视化
  • add是"装进购物车",commit是"下单"
  • log倒序显示历史
查看核心代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Git演练场</title>
<style>
  body { font-family: Consolas, "Microsoft YaHei", monospace; background: #1e1e2e; color: #cdd6f4; margin: 0; padding: 24px; }
  #term { background: #11111b; border-radius: 10px; padding: 18px; min-height: 300px; }
  #input { display: flex; margin-top: 12px; }
  #cmd { flex: 1; background: #313244; border: none; color: #cdd6f4; padding: 12px;
         border-radius: 8px; font-size: 15px; font-family: inherit; }
  .out { color: #a6e3a1; } .err { color: #f38ba8; } .hint { color: #6c7086; font-size: 14px; }
  #viz { margin-top: 16px; display: flex; gap: 20px; }
  .zone { background: #313244; border-radius: 10px; padding: 14px; flex: 1; min-height: 90px; }
  .zone h3 { margin: 0 0 8px; font-size: 14px; color: #89b4fa; }
  .file { background: #45475a; border-radius: 6px; padding: 4px 10px; margin: 4px 0; display: inline-block; margin-right: 6px; }
</style>
</head>
<body>
  <h2>Git 命令演练场</h2>
  <p class="hint">试试:git init → git add index.html → git commit -m "first" → git log</p>
  <div id="viz">
    <div class="zone"><h3>工作区</h3><div id="work"></div></div>
    <div class="zone"><h3>暂存区</h3><div id="stage"></div></div>
    <div class="zone"><h3>仓库(提交历史)</h3><div id="repo"></div></div>
  </div>
  <div id="term"><div class="hint">$ 等待输入……</div></div>
  <div id="input"><input id="cmd" placeholder="输入git命令后回车" autofocus></div>
<script>
  const state = { init: false, work: ['index.html', 'style.css', 'app.js'], stage: [], repo: [] };
  const term = document.getElementById('term');
  function render() {
    document.getElementById('work').innerHTML = state.work.map(f => '<span class="file">' + f + '</span>').join('') || '<span class="hint">空</span>';
    document.getElementById('stage').innerHTML = state.stage.map(f => '<span class="file">' + f + '</span>').join('') || '<span class="hint">空</span>';
    document.getElementById('repo').innerHTML = state.repo.map(c => '<div class="file">📦 ' + c + '</div>').join('') || '<span class="hint">空</span>';
  }
  function print(text, cls) {
    const d = document.createElement('div'); d.textContent = text; d.className = cls || 'out';
    term.appendChild(d); term.scrollTop = term.scrollHeight;
  }
  function run(line) {
    print('$ ' + line, 'hint');
    const parts = line.trim().split(/\s+/);
    if (parts[0] !== 'git') { print('暂只支持git命令', 'err'); return; }
    const sub = parts[1];
    if (sub === 'init') { state.init = true; print('初始化空仓库成功'); }
    else if (!state.init) { print('请先 git init', 'err'); }
    else if (sub === 'add') {
      const f = parts[2];
      if (f === '.') { state.stage.push(...state.work); state.work = []; print('已暂存全部文件'); }
      else if (state.work.includes(f)) { state.work.splice(state.work.indexOf(f), 1); state.stage.push(f); print('已暂存 ' + f); }
      else print('文件不存在:' + (f || ''), 'err');
    }
    else if (sub === 'commit') {
      if (!state.stage.length) { print('暂存区为空', 'err'); return; }
      const msg = parts.slice(3).join(' ').replace(/"/g, '') || 'commit';
      state.repo.push(msg + '(含' + state.stage.length + '个文件)');
      state.stage = [];
      print('[main] ' + msg);
    }
    else if (sub === 'log') { state.repo.slice().reverse().forEach(c => print('commit: ' + c)); if (!state.repo.length) print('暂无提交', 'hint'); }
    else if (sub === 'status') { print('工作区:' + state.work.length + ' 暂存区:' + state.stage.length + ' 已提交:' + state.repo.length); }
    else print('未知子命令:' + sub, 'err');
    render();
  }
  document.getElementById('cmd').addEventListener('keydown', e => {
    if (e.key === 'Enter' && e.target.value.trim()) { run(e.target.value); e.target.value = ''; }
  });
  render();
</script>
</body>
</html>

📋 实习任务书

任务目标:完成计时器模块化重构并用Git管理

任务内容与评分
任务1:为计时器代码补充规范注释(15分)
任务2:拆分render.js/timer.js/main.js三模块(30分)
任务3:git init并完成三次有意义提交(25分)
任务4:故意改坏代码后回滚到上一版本(15分)
任务5:编写项目README.md(15分)

自我评价

📚 课后作业与预习