freeCodeCamp 挑战精讲:用 `<ol>` 与 `<li>` 创建 HTML 有序列表(Create an Ordered List)
2026/9/7 7:34:43 网站建设 项目流程

freeCodeCamp 挑战精讲:用<ol><li>创建 HTML 有序列表(Create an Ordered List)

【免费下载链接】freeCodeCampfreeCodeCamp.org's open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp

本文以 freeCodeCamp 开源课程仓库中的真实挑战 Create an Ordered List 为主体,拆解其教学意图、参考代码、通关步骤与 8 条自动化验收测试的实现逻辑。读者可以借此完整掌握 HTML 有序列表(numbered list)的语法、它与无序列表的差异,同时理解 freeCodeCamp 挑战文件的编写结构(frontmatter、seed、hints 与 solutions),学会如何阅读与解读课程源码中的每一道测试断言。

一、这个挑战在 freeCodeCamp 课程体系中的位置

Create an Ordered List的挑战文件位于curriculum/challenges/english/blocks/basic-html-and-html5/目录,属于经典的「基础 HTML 与 HTML5」课程块(block)。

从课程结构数据可以确认它在体系中的归属链路:

  1. 挑战 IDbad87fee1348bd9aedf08828被登记在课程块清单 curriculum/structure/blocks/basic-html-and-html5.json 的challengeOrder中,紧跟在上一题Create a Bulleted Unordered List(IDbad87fee1348bd9aedf08827)之后——这正是本挑战把「无序列表ul」扩展为「有序列表ol」的教学衔接点;
  2. 该 block 又隶属于responsive-web-design这个 superblock(见 curriculum/structure/superblocks/responsive-web-design.json);
  3. responsive-web-design位于 curriculum/structure/curriculum.json 所列出的超课程块首位,是经典「响应式 Web 设计认证」路径的第一站。

因此,本挑战是很多学习者接触 HTML 列表语义的第一步,也是最典型的「补全式」交互挑战(challengeType 为 0,即html,对应经典编辑器视图,通过测试后提交——见 packages/shared/src/config/challenge-types.ts 中的htmlviewTypessubmitTypes定义)。

二、核心知识点:有序列表<ol>的语法

原文档给出的定义非常精炼,是理解列表语义的起点:

  • HTML 提供了一种用于创建有序列表(ordered list,即编号列表)的专门元素;
  • 有序列表以开标签<ol>开始,内部可包含任意数量的列表项<li>(list item),最后以闭合标签</ol>结束。

文档中的经典示例:

<ol> <li>Garfield</li> <li>Sylvester</li> </ol>

这段代码会被浏览器渲染成GarfieldSylvester两条自动编号的列表项,默认显示为「1.」「2.」。之所以叫「有序」,是因为浏览器会自动为每个<li>维护一个递增序号,顺序本身就是语义信息的一部分(比如排行榜、步骤说明、TOP N 排名)。

与之相对,上一挑战介绍的<ul>(无序列表)则用项目符号(bullet)呈现,列表项之间没有先后次序含义。二者的元素嵌套规则一致:列表项必须直接位于列表容器(<ol><ul>)之内,且单个列表项可以包含文本、图片、链接乃至另一个嵌套列表等丰富内容。

三、原题目标与初始代码

题目要求(instructions)只有一句话:

Create an ordered list of the top 3 things cats hate the most.(为「猫最讨厌的三样东西」创建一个有序列表。)

在 CatPhotoApp 小应用页面中,已经存在一个表示「Things cats love:」(猫喜欢的东西)的<ul>无序列表;学习者需要紧接着在「Top 3 things cats hate:」标题下方,补上一个<ol>有序列表,列出 3 项内容。

挑战的初始代码(seed)如下,其中题目已经给出了h2maina链接、图片和<ul>列表,唯独「Top 3 things cats hate:」之后是空的:

<h2>CatPhotoApp</h2> <main> <p>Click here to view more <a href="#">cat photos</a>.</p> <a href="#"><img src="https://cdn.freecodecamp.org/curriculum/cat-photo-app/relaxing-cat.jpg" alt="A cute orange cat lying on its back."></a> <p>Things cats love:</p> <ul> <li>catnip</li> <li>laser pointers</li> <li>lasagna</li> </ul> <p>Top 3 things cats hate:</p> </main>

注意观察结构:无序列表ul下有 3 个非空的<li><p>Things cats love:</p>是无序列表的前一个兄弟元素,而<p>Top 3 things cats hate:</p>之后到</main>之间就是新<ol>的落点。

四、通关步骤与标准解法

解题思路分为三步:

  1. <p>Top 3 things cats hate:</p>这一行之后、</main>之前另起一行;
  2. 写入开标签<ol>,并在其内部放置 3 个非空、各自闭合的<li>列表项(内容可自由发挥,比如洗澡、打针、剪指甲等);
  3. 写入闭合标签</ol>,保证标签配对完整。

freeCodeCamp 挑战文件会在# --solutions--区块中附带官方参考答案。本挑战的标准解法将占位内容替换为任意三项即可,结构如下:

<h2>CatPhotoApp</h2> <main> <p>Click here to view more <a href="#">cat photos</a>.</p> <a href="#"><img src="https://cdn.freecodecamp.org/curriculum/cat-photo-app/relaxing-cat.jpg" alt="A cute orange cat lying on its back."></a> <p>Things cats love:</p> <ul> <li>catnip</li> <li>laser pointers</li> <li>lasagna</li> </ul> <p>Top 3 things cats hate:</p> <ol> <li>hate 1</li> <li>hate 2</li> <li>hate 3</li> </ol> </main>

五、逐条拆解--hints--自动化测试断言

本挑战的验收不依赖人工检查,而是由浏览器内运行的测试脚本对 DOM 与源代码做断言。把这些断言读懂,就等于理解了「什么才算是合格答案」。

1. 有序列表必须紧跟指定标题

const previousElement = document.querySelector('ol').previousElementSibling; assert.match(previousElement.textContent, /Top 3 things cats hate:/i);

逻辑:页面里必须存在ol,取其「前一个兄弟元素」,且其文本需匹配/Top 3 things cats hate:/ii忽略大小写)。也就是说,新列表必须放在正确的位置,不能随意挪到页面其他地方。

2. 无序列表必须紧跟Things cats love:标题

const previousElement = document.querySelector('ul').previousElementSibling; assert.match(previousElement.textContent, /Things cats love:/i);

防止学习者误改原有<ul>的位置或删除标题段落。

3. 页面只能有一个ul与一个ol

assert.lengthOf(document.querySelectorAll('ul'), 1); assert.lengthOf(document.querySelectorAll('ol'), 1);

querySelectorAll返回所有匹配元素的集合,lengthOf断言其数量必须恰好为 1。这要求学习者在已有结构上补全,而不是另起炉灶或重复添加。

4.ulol内各需恰好 3 个li

assert.lengthOf(document.querySelectorAll('ul li'), 3); assert.lengthOf(document.querySelectorAll('ol li'), 3);

注意ul li是后代选择器:它统计所有嵌套在ul内部的li。数量必须精确为 3,说明「TOP 3」必须名副其实。

5. 标签必须成对闭合

ulolli三类元素,测试都以「正反统计匹配次数」的方式校验闭合标签:

assert.match(code, /<\/ul>/g); assert.strictEqual(code.match(/<\/ul>/g).length, code.match(/<ul>/g).length);

code是学习者提交的源码字符串。/<\/ul>/g全局统计闭合标签出现次数,/<ul>/g统计开标签次数,二者必须严格相等——防止出现漏写</ul>这类「浏览器能容忍、但语义错误」的写法。olli采用同样的成对校验:

assert.match(code, /<\/ol>/g); assert.strictEqual(code.match(/<\/ol>/g).length, code.match(/<ol>/g).length); assert.match(code, /<\/li>/g); assert.match(code, /<li>/g); assert.strictEqual(code.match(/<\/li>/g).length, code.match(/<li>/g).length);

6. 列表项内容不能为空

[...document.querySelectorAll('ul li')].forEach((val) => assert.isNotEmpty(__helpers.removeWhiteSpace(val.textContent)) );

__helpers.removeWhiteSpace是挑战测试运行环境注入的辅助函数,从用法可以推断其作用是剔除文本中的空白字符(空格、换行、缩进),再做isNotEmpty非空断言——即val.textContent在去除纯空白后仍有真实内容。也就是说,<li> </li>这类「空壳列表项」是不能过关的,ol内的 3 个li同样适用这条规则。

六、从文件结构理解 freeCodeCamp 挑战的编写规范

细看这个.md文件本身,它其实是一种带结构化分区的「可执行课程文档」,并非普通说明文章。头部是 YAML frontmatter:

字段取值(本挑战)含义
idbad87fee1348bd9aedf08828全局唯一挑战 ID,也是 block 清单中challengeOrder登记的 ID
titleCreate an Ordered List挑战名称
challengeType0挑战类型,0对应 HTML 型挑战(见 challenge-types.ts),采用经典编辑器视图并以运行测试的方式提交
videoUrlScrimba 视频地址关联的讲解视频
forumTopicId16824对应的论坛讨论主题
dashedNamecreate-an-ordered-list供 URL 使用的连字符化名称,需匹配 slug 规则

正文则按固定顺序使用# --description--# --instructions--# --hints--# --seed--(内含## --seed-contents--)与# --solutions--分区,分别承载「知识讲解」「任务要求」「测试断言」「初始代码」与「参考答案」。

这套格式并非约定俗成,而是由仓库内的工程化工具强制校验:比如 curriculum/schema/challenge-schema.js 就要求challengeType必须是 0–33 之间的数字、dashedName必须通过slugRE正则校验;对应的 curriculum/schema/challenge-schema.test.mjs 会逐文件跑校验快照测试。挑战构建与读取逻辑位于 curriculum/src/get-challenges.ts,前端侧则由tools/client-plugins/gatsby-source-challenges负责把这类.md吸入页面数据层。

对于希望为开源课程贡献新题目或复习旧题的读者而言,直接对照本挑战文件与上述 schema 源码,是理解「一道合格挑战长什么样」的最短路径。

七、小结

通过Create an Ordered List这道题,可以一次掌握三重能力:

  1. HTML 语义层面:会用<ol>+<li>表达「有顺序的编号列表」,并知道它与<ul>在语义与默认渲染上的区别;
  2. 代码规范层面:所有开标签必须成对闭合、列表项内容不能为空、每类列表只需出现一次,这些正是 freeCodeCamp 测试体系对新手 HTML 的硬性要求;
  3. 工程阅读层面:理解了 challengeType、frontmatter、seed 与 hints 的组织方式,具备阅读课程源码与自行验证题目逻辑的基础。

如果你能不看答案、独立让页面通过全部 8 条断言,那么这道经典的基础 HTML 挑战就算真正拿下了。

【免费下载链接】freeCodeCampfreeCodeCamp.org's open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询