首页
/ freeCodeCamp Basic HTML 挑战精讲:用 input 元素创建文本输入框(Create a Text Field)

freeCodeCamp Basic HTML 挑战精讲:用 input 元素创建文本输入框(Create a Text Field)

2026-09-06 19:27:08作者:胡唯隽

本篇文章以 freeCodeCamp 开源课程仓库中 "Basic HTML and HTML5" 板块的第 17 个挑战 Create a Text Field(挑战文件 bad87fee1348bd9aedf08829.md)为核心,系统讲解 HTML <input type="text"> 文本输入框的语法与"空元素(void element)"这一底层概念,并逐段拆解挑战的 descriptioninstructionshintsseedsolutions 结构。读完本文,你将掌握文本输入框的标准写法、input 元素不可有闭合标签的原因,理解 freeCodeCamp 挑战文件是如何被"机器可读"地设计、校验与自动判题的,并能跟随 CatPhotoApp 项目一路构建出可提交的表单。

一、挑战档案与它在课程中的位置

先看挑战文件的 YAML frontmatter 头:

---
id: bad87fee1348bd9aedf08829
title: Create a Text Field
challengeType: 0
videoUrl: 'https://scrimba.com/p/pVMPUv/c2EVnf6'
forumTopicId: 16823
dashedName: create-a-text-field
---

其中几个字段值得关注:

字段 含义
id bad87fee1348bd9aedf08829 全局唯一的挑战 ID,既是文件名,也是数据库与测试中定位该挑战的稳定标识
challengeType 0 挑战类型。在 packages/shared/src/config/challenge-types.ts 第 1 行定义了 const html = 0;,即类型 0 表示经典 HTML 练习
videoUrl Scrimba 教学视频 该挑战配套的短视频讲解
forumTopicId 16823 关联论坛讨论主题的编号
dashedName create-a-text-field URL 友好的短名称

这个挑战不是孤立存在的。查询板块定义文件 basic-html-and-html5.json 中的 challengeOrder 数组可以发现,整个板块共 28 个挑战,由前向后依次推进:从 h2 标题、p 段落、图片 <img>、超链接 <a>、无序列表 <ul>、有序列表 <ol>,再到本关——第一次引入"表单交互"概念,随后依次是 "Add Placeholder Text to a Text Field"、"Create a Form Element"、"Add a Submit Button to a Form"、"Use HTML5 to Require a Field"、单选按钮与复选框等。

也就是说,本关是整条"构建网页表单"学习路径的起点:在此之后文本输入框会被装进 <form>、加上 placeholder、配上 submit 按钮,最终形成完整的用户输入机制。

二、核心知识点:input 元素与文本输入框

挑战描述原文非常简洁,核心只有两句话:

  • input 元素是从用户那里获取输入的一种便捷方式;
  • 创建一个文本输入框只需一行代码:
<input type="text">

展开来看,这行代码包含两个组成部分:

  1. 标签名 inputinput 是 HTML 中专门用于收集用户输入的内联表单控件。根据 type 属性的不同取值,它可以呈现为文本框、密码框、数字框、邮箱框、日期选择器、单选按钮等多种形态。
  2. type 属性type="text" 显式声明这是一个单行纯文本输入框。在 HTML5 中,type 默认值本来就是 text,但显式写出是更严谨、可读性更好的实践——这也是后续挑战 hints 会专门用 input[type=text] 选择器来校验的原因。

这个元素在浏览器中渲染为一个可键入字符的单行编辑框。值得注意的是:本挑战只要求在页面中加入一个输入框,并不要求它具备提交能力——把文本框"交给"服务器、实现真正提交,是后面几个挑战(<form> 元素与 submit 按钮)的任务。这种循序渐进、一次只引入一个新概念的设计,正是 freeCodeCamp 挑战体系的典型教学策略。

三、深入理解:为什么 input 是"空元素(void element)"

挑战描述特别强调了一句话:

Note that input is a void element.

这是本关最容易出错、也最值得深挖的知识点。"void element(空元素 / 无内容元素)"是 HTML 规范术语,指没有内容、也没有闭合标签的元素。它只能以自闭合形式或仅写开始标签形式出现:

<!-- 合法:HTML5 中 void 元素不应写闭合标签 -->
<input type="text">

<!-- 也是合法写法(XML/XHTML 风格的自闭合,浏览器同样接受) -->
<input type="text"/>

而下面这种"既写开始标签又写闭合标签"的写法是不合法的

<!-- 非法:input 没有内容,不允许闭合标签 -->
<input type="text"></input>

HTML 标准中常见的 void 元素除 input 外还有 img(图片)、br(换行)、hr(水平分隔线)、metalink 等。它们的共同特征是:自身即承载全部信息(通过属性),不需要也不可能包裹任何子内容。对比一下同板块中已学过的元素就能理解这种差异:

元素 是否有闭合标签 原因
ph2aulolli 需要包裹文本或子元素作为"内容"
imginputbrhr void 元素,没有内容模型,数据全靠属性表达

这一知识点在后续挑战中会被反复验证:例如下一关 "Add Placeholder Text to a Text Field"(bad87fee1348bd9aedf08830.md)的 hints 中就有专门的断言 assert.notMatch(code, /<input.*\/?>.*<\/input>/gi),用于确保学习者没有给 input 错误地加上闭合标签。可见"void 元素"不是细枝末节的考点,而是整个表单学习阶段持续强调的规范。

四、逐句读懂题目指令与初始代码(seed)

4.1 指令解读

挑战的 --instructions-- 只有一句话:

Create an input element of type text below your lists.

即:在页面中已有的两个列表之后,新增一个 <input type="text">。注意"below your lists"的约束——正确的插入位置是在 <ol> 列表的 </ol> 之后、</main> 之前。

4.2 seed 初始代码分析

挑战提供了一段完整的 CatPhotoApp 初始代码作为练习起点(即 --seed-contents--):

<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>flea treatment</li>
    <li>thunder</li>
    <li>other cats</li>
  </ol>


</main>

这段代码相当于前面十几个挑战的"集大成",涵盖了:

  • h2 页面主标题;
  • 包裹在 p 中、指向 # 死链接的 <a> 锚点;
  • <a> 包起来的 <img> 图片(alt 属性描述了图片内容);
  • ul 无序列表 + 3 个 li
  • ol 有序列表 + 3 个 li
  • 语义化容器 <main>

而学习者的任务就是在倒数第二个空行处补上文本框。可以看到 seed 中 <ol></main> 之间留有空白行,这正是设计给学习者"插入新元素"的位置提示。

五、hints 背后的自动判题机制

挑战的 --hints-- 段不仅写给学习者,更是机器判题的依据。本关唯一的 hint 是:

assert.isNotEmpty(document.querySelectorAll('input[type=text]'));

这条断言逐层拆解:

  1. document.querySelectorAll('input[type=text]'):在用户渲染出的完整 DOM 中,查找所有 type 属性为 textinput 元素,返回一个类数组的 NodeList;
  2. assert.isNotEmpty(...):断言该 NodeList 不为空,即页面中确实存在至少一个 input[type=text]

可以看出,freeCodeCamp 的自动判题是在浏览器环境中直接对学习者代码渲染后的真实 DOM 做断言,而不是做简单的字符串匹配。从 assert.isNotEmpty 的调用风格可以推断,其运行时采用 Chai 风格的断言库,这与同板块其他挑战(如后续挑战中出现的 assert.strictEqualassert.match)保持一致。这种"运行真实代码 + DOM 级验证"的评测方式,保证了答案即便在标签书写顺序、空白字符上有所差异,只要语义正确就能通过。

挑战类型与评测方式之间有明确的映射关系。在 packages/shared/src/config/challenge-types.ts 中,challengeType: 0 被定义并命名为 html;同时 curriculum/schema/challenge-schema.js 对挑战文件做出强校验(约第 180 行),要求 challengeType 必须是 033 之间的数字,并针对不同类型的挑战要求不同的必需字段(例如视频类挑战需要 videoId,填空题类挑战需要 inputType 等)。这意味着每个 .md 挑战文件在被正式纳入课程前,都要通过 JSON Schema 级的格式验证,保证 --description----instructions----hints----seed----solutions-- 等区块结构完整且类型合法。

六、参考解答:注意官方把文本框放进了 form

--solutions-- 段给出了官方参考实现。与 seed 相比,唯一的差异是在列表之后新增了一个 <form> 包裹的文本输入框:

<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>flea treatment</li>
    <li>thunder</li>
    <li>other cats</li>
  </ol>
  <form>
    <input type="text">
  </form>
</main>

官方解答比题目要求多走了一步——它把 <input type="text"> 包进了一个空 <form> 元素。这样做的用意有两层:一是从语义上讲,input 作为表单控件理应存在于 <form> 之中;二是为紧随其后的挑战做铺垫——下一关将在同一个 <form> 内给 input 添加 placeholderbad87fee1348bd9aedf08830.md),再下一关会让 <form> 带上 action 属性(bad87fee1348bd9aede08830.md),随后加入 type="submit" 的按钮(bad87fee1348bd9aedd08830.md),最终让整个表单真正把用户输入的数据提交到指定 URL。

七、由本关引申的 input 常用属性速览

尽管本关只要求最简写法,理解 input 的常用属性能帮助你判断后续挑战的演进逻辑(后续每一关基本都是在"补一个属性"):

属性 作用 对应后续挑战
type 定义控件类型,text 表示单行文本 本关
placeholder 输入前显示在框内的灰色提示文字 Add Placeholder Text to a Text Field
action(在 form 上) 提交数据的去向 URL Create a Form Element
type="submit"(在 button 上) 触发表单提交 Add a Submit Button to a Form
required 声明该字段必填 Use HTML5 to Require a Field
name 提交时标识该字段的键名 表单提交数据格式的基础
value 控件当前值(或默认值) 单选/复选框相关挑战

从知识树角度看,本关引入的 <input type="text"> 是理解后续 radiocheckboxsubmit 等所有输入型控件的基础——它们的差异本质上只是 type 属性取值不同而已。

八、在仓库中如何定位、校验与进一步研究本挑战

本关对应的源文件是 curriculum/challenges/english/blocks/basic-html-and-html5/bad87fee1348bd9aedf08829.md,英文原文是其他语言翻译的基准(仓库中的 i18n-curriculum 目录用于存放各语言的翻译成果)。若想在本地完整验证这类挑战文件,可以关注以下仓库内证据链:

本挑战的全部要点可以浓缩为一句话:用一个 void 元素 input,配合 type="text" 属性,在列表下方放一个文本输入框——看似简单的一步,却同时引入了"表单控件"和"空元素"两个贯穿后续所有表单类挑战的基础概念,是整个 freeCodeCamp CatPhotoApp 表单学习线真正意义上的起点。

登录后查看全文
热门项目推荐
相关项目推荐