Menu
CoddyTech

HTML 页面

本课属于 Coddy Node.js 学习旅程的“Express 基础”单元。第 10 课,共 23 课。

Recipe Box 现在会把 HTML 字符串和转义练习变成一个页面。为每个食谱创建一个链接。链接的 href 用来选择目标位置,标签之间的文本就是读者看到的标签。

const link = `<a href="/books/${book.id}">${escapeHtml(book.title)}</a>`;

html.js 中提供了这个辅助函数。对每个标题应用它,同时将你自己的链接标签保留为标记。使用 map 创建链接,再用 join 将它们合并为一个字符串。直接在模板字符串中放入数组会在链接之间插入逗号。res.send 会将完整页面发送给浏览器。

<ul> 用来存放列表,<li> 用来包裹每个列表项。未转义的标记可能会更改页面,或在访客的浏览器中运行脚本;即使标题来自你自己的数据文件,也要逐个转义。

challenge icon

挑战

简单

这一步会打开课程中准备好的 Recipe Box 项目,而不是你在 Status Codes 中的项目文件(包括 server.js)。你之前的工作仍保留在原来的课中。编辑 server.js 前,先阅读提供的文件。这份项目副本包含 Recipe Box 路由、状态码和共享的 html.js 辅助工具。

现在,主页会成为一个真正的页面:列出所有菜谱,每个菜谱都链接到自己的页面。

  1. 在 server.js 中,从 ./html.js 导入提供的 escapeHtml 辅助函数。
  2. 修改 / 路由,让它发送 HTML 页面,而不是欢迎文本。页面中每个菜谱都有一个链接,指向该菜谱的页面,并显示菜谱标题。菜谱 2 的链接如下:<a href="/recipes/2">Pancakes</a>。使用列表很合适:每个链接放在一个 <li> 项中,所有项目都放在一个 <ul> 中。你可以从一个标题开始:<h1>Recipe Box</h1>。
  3. 将每个标题传入 escapeHtml,再放入页面。这样,Fish & Chips 会以 Fish &amp; Chips 的形式进入页面,浏览器会将其显示为 Fish & Chips。
  4. 使用 map 构建这些项目,并用空字符串将它们连接起来。如果直接把数组放进模板字符串中,项目之间会出现逗号。

试试看:点击“运行”,然后访问 /。响应会以包含 4 个链接的页面形式呈现。点击 Fish & Chips:/recipes/4 页面会打开,并显示 Fish & Chips。

亲手试试

import express from 'express';
import { recipes } from './data.js';

const app = express();

app.get('/', (req, res) => {
    res.send('Welcome to Recipe Box');
});

// type('text') 会发送纯文本,所以每个标题都会单独显示在一行。
app.get('/recipes', (req, res) => {
    const { tag } = req.query;
    const list = tag ? recipes.filter((recipe) => recipe.tags.includes(tag)) : recipes;
    res.type('text').send(list.map((recipe) => recipe.title).join('\n'));
});

app.get('/recipes/:id', (req, res) => {
    const recipe = recipes.find((r) => r.id === Number(req.params.id));
    if (!recipe) {
        res.status(404).send('No such recipe');
        return;
    }
    res.send(recipe.title);
});

app.get('/api/recipes', (req, res) => {
    res.json(recipes);
});

app.get('/api/recipes/:id', (req, res) => {
    const recipe = recipes.find((r) => r.id === Number(req.params.id));
    if (!recipe) {
        res.status(404).json({ error: 'No such recipe' });
        return;
    }
    res.json(recipe);
});

app.get('/about', (req, res) => {
    res.send('Recipe Box collects family recipes.');
});

app.listen(3000, () => {
    console.log('Recipe Box is running on port 3000');
});
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

Express 基础中的所有课

自己练习: Express 在线编辑器