第 16 章 · 毕业项目:响应式课程门户
本章是 前端开发入门 模块的毕业考核:在 academy-demo 基础上交付一个响应式课程门户,整合 HTML/CSS/JS、ES6+、Fetch、Vite 工程化、性能、a11y 与 SEO,达到可演示、可部署、可验收标准。
建议用时:12~16 小时(分 3~4 天完成)。
16.1 项目背景与目标
贤紫技术学院需要一套面向学员的课程门户:展示课程目录、章节详情、学习进度与待办笔记,适配手机与桌面,可部署至静态托管或学院 CDN。
| 目标 | 说明 |
|---|
| 业务完整 | 首页、课程列表、课程详情、个人待办 |
| 技术综合 | Vite + 原生 JS 模块 + Fetch/Mock |
| 体验达标 | Lighthouse 移动端 Performance ≥ 85 |
| 合规底线 | 基础 a11y + SEO meta + 无 XSS 隐患 |
| 可交付 | README + 构建产物 + 演示 URL |
16.2 功能需求(Must / Should / Could)
Must(必须,占分 70%)
| 模块 | 功能点 |
|---|
| 首页 | 学院介绍、精选课程、导航至列表 |
| 课程列表 | 卡片展示、按关键词搜索(防抖)、按标签筛选 |
| 课程详情 | 章节大纲、学时、返回列表 |
| 待办 | 增删改查、localStorage 或 API 持久化 |
| 响应式 | 320px~1440px 无横向滚动 |
| 工程化 | npm run dev / build / preview 可用 |
Should(建议,占分 20%)
| 功能 | 说明 |
|---|
| 深色模式 | 切换 + localStorage |
| 收藏课程 | Set 存储 id 列表 |
| 加载/错误态 | skeleton、重试按钮 |
| 部署文档 | Nginx 或对象存储步骤 |
Could(加分,占分 10%)
| 功能 | 说明 |
|---|
| 学习进度 | 每章完成百分比 |
| JSON-LD Course | 结构化数据 |
| PWA 离线壳 | service worker(进阶) |
16.3 推荐目录结构
academy-demo/
├── index.html # 首页
├── courses.html # 课程列表
├── course.html # 详情(?id=fe-09)
├── todo.html # 待办
├── package.json
├── vite.config.js
├── .env.development
├── .env.production
├── public/
│ ├── favicon.svg
│ └── mock/
│ ├── courses.json
│ └── chapters-fe-09.json
├── src/
│ ├── main.js # 首页入口
│ ├── courses.js # 列表页入口
│ ├── course-detail.js
│ ├── todo.js
│ ├── style/
│ │ ├── tokens.css # 设计令牌
│ │ ├── base.css
│ │ ├── layout.css
│ │ └── components.css
│ ├── api/
│ │ └── client.js
│ ├── components/
│ │ ├── header.js
│ │ ├── course-card.js
│ │ ├── search-bar.js
│ │ └── todo-item.js
│ ├── utils/
│ │ ├── debounce.js
│ │ ├── escape-html.js
│ │ └── storage.js
│ └── data/
│ └── constants.js
└── README.md
| 路径 | 职责 |
|---|
tokens.css | 颜色、间距、字体、断点变量 |
api/client.js | 统一 Fetch + 错误 |
components/ | 可复用 UI 工厂函数 |
utils/ | 纯函数,无 DOM 副作用 |
16.4 数据模型
课程 Course
// 逻辑类型(可用 JSDoc)
// { id: string, title: string, desc: string, hours: number,
// tags: string[], cover: string, level: 'beginner'|'intermediate' }
章节 Chapter
{
"courseId": "fe-09",
"chapters": [
{ "slug": "ch09", "title": "DOM 操作与事件", "freePreview": false }
]
}
待办 Todo
{ "id": "uuid", "text": "完成 ch16 毕业项目", "done": false, "courseId": "fe-16" }
public/mock/courses.json 至少包含前端课程 ch01~ch16 元数据,便于离线演示。
16.5 分步实现(建议顺序)
| 阶段 | 天数 | 任务 | 产出 |
|---|
| D1 | 第 1 天 | 初始化 Vite、tokens、Header/Footer 组件 | 三页空壳 + 统一导航 |
| D2 | 第 2 天 | 课程列表 + 搜索防抖 + 标签筛选 | courses.html 功能完整 |
| D3 | 第 3 天 | 详情页读 query + mock 章节;Todo 页 CRUD | 核心链路打通 |
| D4 | 第 4 天 | 响应式细调、Lighthouse、a11y、SEO、build 部署 | 可提交终版 |
16.5.1 阶段一:布局与导航
// src/components/header.js
export function renderHeader(active = 'home') {
const nav = document.createElement('header');
nav.className = 'site-header';
nav.innerHTML = `
<a class="logo" href="/">贤紫技术学院</a>
<nav aria-label="主导航">
<a href="/" ${active === 'home' ? 'aria-current="page"' : ''}>首页</a>
<a href="/courses.html" ${active === 'courses' ? 'aria-current="page"' : ''}>课程</a>
<a href="/todo.html" ${active === 'todo' ? 'aria-current="page"' : ''}>待办</a>
</nav>
`;
return nav;
}