recursal/MDN huggingface dataset:
书籍详细信息页面
========

*书籍详细信息页面*需要呈现指定书籍（`Book`，使用自动生成的 `_id` 字段值进行标识）的信息，以及图书馆中每一个关联的副本（`BookInstance`）的信息。无论我们在哪里呈现一个作者、种类，或书籍实例，都应该链接到关联的详细信息页面。

控制器
---

打开 **/controllers/bookController.js**，找到导出的 `book_detail()` 控制器方法，并将其替换为以下代码。


```js
// 显示特定书籍的详细信息页面。
exports.book_detail = asyncHandler(async (req, res, next) => {
  // 获取书籍的详细信息，以及特定书籍的实例
  const [book, bookInstances] = await Promise.all([
    Book.findById(req.params.id).populate("author").populate("genre").exec(),
    BookInstance.find({ book: req.params.id }).exec(),
  ]);

  if (book === null) {
    // 没有结果。
    const err = new Error("Book not found");
    err.status = 404;
    return next(err);
  }

  res.render("book\_detail", {
    title: book.title,
    book: book,
    book\_instances: bookInstances,
  });
});
```


**备注：** 我们不需要用 require 导入任何额外的模块，因为我们在实现主页控制器时已经导入了依赖项。

此方法与类别详细信息页面描述的方法完全相同。路由控制器函数使用 `Promise.all()` 并行查询指定的书籍（`Book`）以及它的相关副本（`BookInstance`）。如果没有找到匹配的书籍，就会返回一个带有“404: Not Found”错误的 Error 对象。如果找到了书籍，那么就会使用“book\_detail”模板呈现检索到的数据库信息。由于“title”键用于给网页命名（如“layout.pug”中定义的标题），所以这次我们在渲染网页时传递了 `results.book.title`。

视图
--

创建 **/views/book\_detail.pug** 并添加以下文本。


```pug
extends layout

block content
  h1 Title: #{book.title}

  p #[strong Author:]
    a(href=book.author.url) #{book.author.name}
  p #[strong Summary:] #{book.summary}
  p #[strong ISBN:] #{book.isbn}
  p #[strong Genre:]
    each val, index in book.genre
      a(href=val.url) #{val.name}
      if index < book.genre.length - 1
        |,

  div(style='margin-left:20px;margin-top:20px')
    h4 Copies

    each val in book\_instances
      hr
      if val.status=='Available'
        p.text-success #{val.status}
      else if val.status=='Maintenance'
        p.text-danger #{val.status}
      else
        p.text-warning #{val.status}
      p #[strong Imprint:] #{val.imprint}
      if val.status!='Available'
        p #[strong Due back:] #{val.due\_back}
      p #[strong Id:]
        a(href=val.url) #{val.\_id}

    else
      p There are no copies of this book in the library.
```


在这个模板中，几乎所有内容都在先前的章节演示过了。

**备注：** 与本书相关的类别列表在模板中的实现如下。除了最后一个之外，这会在与本书相关的每个类别后面添加一个逗号。


```pug
  p #[strong Genre:]
    each val, index in book.genre
      a(href=val.url) #{val.name}
      if index < book.genre.length - 1
        |,
```


它看起来像是？
-------

运行本应用，并打开浏览器访问 `http://localhost:3000/`。选择 *All books* 链接，然后选择其中某一书籍。如果所有内容都设置正确了，你的页面应类似于以下屏幕截图。

![书籍详细信息页面——Express 本地图书馆网站](/zh-CN/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Book_detail_page/locallibary_express_book_detail.png)

下一步
---

* 回到 Express 教程 5：呈现图书馆数据
* 继续教程 5 的下一个部分：作者详细信息页面
作者细节页面
======

作者细节页面需要呈现指定作者`Author`的信息，使用 `_id` 字段的值（自动产生）识别，接着是这个作者的所有书本物件`Book`的列表。

控制器
---

打开 **/controllers/authorController.js**。

在档案最上方，加入底下几行，引入 async 和 Book 模组 (作者细节页面需要它们)。


```js
var async = require("async");
var Book = require("../models/book");
```


找到 exported `author_detail()` 控制器方法，并用底下代码置换。


```js
// Display detail page for a specific Author.
exports.author\_detail = function (req, res, next) {
  async.parallel(
    {
      author: function (callback) {
        Author.findById(req.params.id).exec(callback);
      },
      authors\_books: function (callback) {
        Book.find({ author: req.params.id }, "title summary").exec(callback);
      },
    },
    function (err, results) {
      if (err) {
        return next(err);
      } // Error in API usage.
      if (results.author == null) {
        // No results.
        var err = new Error("Author not found");
        err.status = 404;
        return next(err);
      }
      // Successful, so render.
      res.render("author\_detail", {
        title: "Author Detail",
        author: results.author,
        author\_books: results.authors_books,
      });
    },
  );
};
```


此处的控制器方法使用 `async.parallel()`，用平行的方式，查询作者 `Author`和相应的书本实例，并附加上绘制本页面的回调，如果 2 个要求都成功完成，就运行回调。这个方式，就跟前面的种类细节页面所说明的完全相同。

视图
--

创建 **/views/author\_detail.pug** ，並複制貼上底下的文字。


```js
extends layout

block content

  h1 Author: #{author.name}
  p #{author.date_of_birth} - #{author.date_of_death}

  div(style='margin-left:20px;margin-top:20px')

    h4 Books

    dl
      each book in author_books
        dt
          a(href=book.url) #{book.title}
        dd #{book.summary}

      else
        p This author has no books.
```


本模板里的所有事物，都在先前的章节演示过了。

它看起來像是？
-------

运行本应用，并打开浏览器访问 http://localhost:3000/。选择 All Authors 连结，然后选择一个作者。如果每个东西都设定正确了，你的网站看起来应该会像底下的截图。

![Author Detail Page - Express Local Library site](/zh-CN/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Author_detail_page/locallibary_express_author_detail.png)

**备注：** 作者的出生与死亡日期的外观很丑！我们将在本文最后的自我挑战处理它。

下一步
---

* 回到 Express 教程 5: 呈现图书馆数据
* 继续教程 5 的下一个部分 : 书本实例细节页面和自我挑战
书本实例列表页面
========

接下来，我们将实作图书馆中所有书本实例 (`BookInstance`) 的列表页面。这个页面需要包含与每个 `BookInstance` (链接到其详细信息页面) 关联的书本 `Book` 标题，以及`BookInstance`模型中的其他信息，包含每个副本的状态，印记和唯一 ID。唯一 ID 的文字，应该链接到 `BookInstance` 详细信息页面。

控制器
---

`BookInstance`列表控制器函数，需要获取所有书本实例的列表，填充关联的书本信息，然后将列表传递给模板以进行呈现。

打开 **/controllers/bookinstanceController.js**。找到导出的 `bookinstance_list()` 控制器方法，并用以下代码替换它（更改后的代码以粗体显示）。


```js
// Display list of all BookInstances.
exports.bookinstance\_list = function (req, res, next) {
  BookInstance.find()
    .populate("book")
    .exec(function (err, list\_bookinstances) {
      if (err) {
        return next(err);
      }
      // Successful, so render
      res.render("bookinstance\_list", {
        title: "Book Instance List",
        bookinstance\_list: list_bookinstances,
      });
    });
};
```


此方法使用模型的`find()`函数，返回所有`BookInstance`对象。然后它将一个调用，以菊花链方式连接到`populate()`，附加书本`book`字段，这将使用完整的`Book`文档，替换每个`BookInstance`存储的书本 ID。

成功时，传递给查询的回调，会呈现 **bookinstance\_list** (.pug) 模板，并将标题`title`和书籍实例列表`bookinstance_list`作为变量传递。

视图
--

创建 **/views/bookinstance\_list.pug**，并复制粘贴下面的文本。


```pug
extends layout

block content
  h1= title

  ul
  each val in bookinstance\_list
    li
      a(href=val.url) #{val.book.title} : #{val.imprint} -
      if val.status=='Available'
        span.text-success #{val.status}
      else if val.status=='Maintenance'
        span.text-danger #{val.status}
      else
        span.text-warning #{val.status}
      if val.status!='Available'
        span  (Due: #{val.due\_back} )

  else
    li There are no book copies in this library.
```


这个视图与其他视图非常相似。它扩展了布局，替换*内容*区块，显示从控制器传入的标题 `title`，并遍历 `bookinstance_list` 中的所有书籍副本。对于每个副本，我们都会显示它的状态（用颜色编码），如果书本不可用，则显示其预期返回日期。这里引入了一个新功能——我们可以在标签之后使用点符号表示法，来指定一个类别。因此，`span.text-success` 将被编译为 `<span class="text-success">`（也可以用 Pug 编写为 `span(class="text-success")`）。

它看起来像是？
-------

运行本应用，打开浏览器访问 `http://localhost:3000/`，然后选择 *All book-instances* 链接。假如每个东西都设置正确了，你的网站看起来应该像是底下的截图。

![BookInstance List Page - Express Local Library site](/zh-CN/docs/Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_list_page/locallibary_express_bookinstance_list.png)

下一步
---

* 回到 Express 教程 5: 呈现图书馆数据
* 继续教程 5 下个部分：日期格式化与使用 moment
作者清单面页、分类清单页面挑战
===============

作者列表页面，需要呈现数据库中所有作者的列表，有每位作者的名字，并连结到作者详细内容页面。出生与死亡日期应该在名字后面，并且在同一列。

控制器
---

作者列表控制器函数，需要获取所有作者实例的列表，然后将这些实例传递给模板进行渲染。

打开 **/controllers/authorController.js**。在文件顶部附近，找到导出的 `author_list()` 控制器方法，并将其替换为以下代码（更改后的代码以粗体显示）。


```js
// Display list of all Authors.
exports.author\_list = function (req, res, next) {
  Author.find()
    .sort([["family\_name", "ascending"]])
    .exec(function (err, list\_authors) {
      if (err) {
        return next(err);
      }
      //Successful, so render
      res.render("author\_list", {
        title: "Author List",
        author\_list: list_authors,
      });
    });
};
```


该方法使用模型的 `find()`, `sort()` 和 `exec()` 函数，以返回所有 `Author` 对象，并按 `family_name` 的字母顺排列。传递给 `exec()` 方法的回调被调用，并将传入任何错误（或 `null`）作为第一个参数，或者成功时，传入所有作者列表。如果出现错误，则调用带有错误值的下一个中间件函数，如果没有错误，则呈现 **author\_list**（.pug）模板，传递页面标题 `title`，和作者列表（`author_list`）。

视图
--

打开 **/views/author\_list.pug** ，用底下文字取代它的内容。


```js
extends layout

block content
  h1= title

  ul
  each author in author_list
    li
      a(href=author.url) #{author.name}
      | (#{author.date_of_birth} - #{author.date_of_death})

  else
    li There are no authors.
```


如同我们其他的模板，上面视图也依照着同样的模式。

它看起來像是？
-------

运行本应用，并打开浏览器访问 http://localhost:3000/ 。然后选择所有作者 All authors 连结。如果每个东西都设定正确了，页面看起来应该像底下的截图。

![Author List Page - Express Local Library site](/zh-CN/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Author_list_page/locallibary_express_author_list.png)

**备注：** 作者生命日期的外观是丑陋的！你可以使用我们用于`BookInstance` 列表的相同方法（将生命周期的虚拟属性，添加到 `Author` 模型），来改进此方法。

但是，这次缺少日期，除非严格模式生效，否则将忽略对不存在的属性的引用。`moment()`返回当前时间，并且你不希望将缺少的日期格式化为就像今天一样。

解决此问题的一种方法，是定义返回格式化日期的函数内容，以便返回空字符串，除非日期实际存在。例如：

`return this.date_of_birth ? moment(this.date_of_birth).format('YYYY-MM-DD') : '';`

种类列表页面—自我挑战！
------------

在这个部分，你应该实作你自己的种类列表页面。该页面应显示数据库中所有种类的列表，每个种类都链接到其关联的详细信息页面。预期结果的屏幕截图如下所示。

![Genre List - Express Local Library site](/zh-CN/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Author_list_page/locallibary_express_genre_list.png)

种类列表控制器功能，需要获取所有种类实例的列表，然后将这些实例传递给模板进行渲染。

1. 你需要在 **/controllers/genreController.js** 中编辑`genre_list()`。
2. 实现方式几乎与`author_list()`控制器完全相同。
    * 按名称以上升顺序，对结果进行排序。
3. 要呈现的模板，应命名为 **genre\_list.pug**。
4. 要呈现的模板应该传递变量`title`（'Genre List'）和种类列表`genre_list`（从`Genre.find()`回调返回）。
5. 该视图应与上面的屏幕截图/要求相匹配（这应该与作者列表视图具有非常相似的结构/格式，除了种类没有日期）。
下一步
---

回到 Express 教程 5: 呈现图书馆数据

继续教程 5 下一個部分：种类细节页面
书本实例细节页面、与自我挑战
==============

书本实例细节页面
--------

`BookInstance`细节页面，需要呈现每一个`BookInstance`的信息，用 `_id` 字段值（自动产生）做识别。它包含了 `Book` 名称 (也是一个连结，连到 书本细节页面)，接着是纪录中的其他的信息。

### 控制器

打开 **/controllers/bookinstanceController.js**，找到 exported `bookinstance_detail()` 控制器方法，并替换以下代码。


```js
// Display detail page for a specific BookInstance.
exports.bookinstance\_detail = function (req, res, next) {
  BookInstance.findById(req.params.id)
    .populate("book")
    .exec(function (err, bookinstance) {
      if (err) {
        return next(err);
      }
      if (bookinstance == null) {
        // No results.
        var err = new Error("Book copy not found");
        err.status = 404;
        return next(err);
      }
      // Successful, so render.
      res.render("bookinstance\_detail", {
        title: "Book:",
        bookinstance: bookinstance,
      });
    });
};
```


该方法使用从 URL（使用路由）中提取的特定书本实例的 ID，调用`BookInstance.findById()`，并通过请求参数（`req.params.id`），在控制器中访问。然后调用`populate()`来获取相关`Book`的详细信息。

### 视图

创建 **/views/bookinstance\_detail.pug**，并复制到下面的内容中。


```js
extends layout

block content

  h1 ID: #{bookinstance._id}

  p #[strong Title:]
    a(href=bookinstance.book.url) #{bookinstance.book.title}
  p #[strong Imprint:] #{bookinstance.imprint}

  p #[strong Status:]
    if bookinstance.status=='Available'
      span.text-success #{bookinstance.status}
    else if bookinstance.status=='Maintenance'
      span.text-danger #{bookinstance.status}
    else
      span.text-warning #{bookinstance.status}

  if bookinstance.status!='Available'
    p #[strong Due back:] #{bookinstance.due_back}
```


本模组中的所有东西，都在先前的章节演示过了。

### 它看起來像是？

运行本应用，并打开浏览器访问 http://localhost:3000/。选择 All book-instances 连结，然后选择其中一本。如果每个东西都设定正确了，你的网站看起来应该像是底下的截图。

![BookInstance Detail Page - Express Local Library site](/zh-CN/docs/Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_detail_page_and_challenge/locallibary_express_bookinstance_detail.png)

自我挑战
----

目前，我们网站上显示的大多数日期，都使用默认的 JavaScript 格式（例如 *Tue Dec 06 2016 15:49:58 GMT+1100*（AUS 东部夏令时间）。本文的挑战，是改善作者`Author`生命周期日期显示的外观信息（死亡/出生日期）和 BookInstance 详细信息页面，使用格式：December 6th, 2016。

**备注：** 你可以使用与我们用于 Book Instance List 的相同方法（将生命周期的虚拟属性，添加到`Author`模型，并使用moment来设置日期字符串的格式）。

这一挑战的要求：

1. 用 BookInstance 详细信息页面中的 `due_back_formatted` 替换 `due_back`。
2. 更新作者模块以添加寿命虚拟属性。寿命应該有两个值： *date\_of\_birth - date\_of\_death，這*两个值的格式与 `BookInstance.due_back_formatted`的日期格式相同。
3. 在当前使用`date_of_birth` 和 `date_of_death`的所有视图中，使用 `Author.lifespan` 。
下一步
---

* 回到 Express 教程 5: 呈现图书馆数据
种类细节页面
======

种类细节页面，需要利用`_id` 字段值 (自动生成) ，以呈现特定种类实例的信息。此页面应该呈现种类名称，各个种类的所有书本列表 (每本书都连结到书本的细节页面)。

控制器
---

打开 **/controllers/genreController.js** ，并在档案最上方引用 async 和 Book 模组。


```js
var Book = require("../models/book");
var async = require("async");
```


找到导出的 `genre_detail()` 控制器方法，并将其替换为以下代码。


```js
// Display detail page for a specific Genre.
exports.genre\_detail = function (req, res, next) {
  async.parallel(
    {
      genre: function (callback) {
        Genre.findById(req.params.id).exec(callback);
      },

      genre\_books: function (callback) {
        Book.find({ genre: req.params.id }).exec(callback);
      },
    },
    function (err, results) {
      if (err) {
        return next(err);
      }
      if (results.genre == null) {
        // No results.
        var err = new Error("Genre not found");
        err.status = 404;
        return next(err);
      }
      // Successful, so render
      res.render("genre\_detail", {
        title: "Genre Detail",
        genre: results.genre,
        genre\_books: results.genre_books,
      });
    },
  );
};
```


该方法使用`async.parallel()`，并行查询类型名称及其相关联的书本，并在（如果）两个请求成功完成时，回调呈现页面。

所需种类记录的 ID，在 URL 的末尾编码，并根据路由定义（**/genre/:id**）自动提取。通过请求参数（`req.params.id`）在控制器内访问 ID。它在 `Genre.findById()` 中用于获取当前种类。它还用于获取符合当前种类的所有`Book`对象，就是在种类字段中具有种类 ID 的那些 `Book.find({ 'genre': req.params.id })`。

**备注：** 如果数据库中不存在该类型（即它可能已被删除），则`findById()`将成功返回，但没有结果。在这种情况下，我们想要显示一个“未找到”页面，因此我们创建一个`Error`对象，并将其传递给链中的下一个中间件函数`next`。


```js
if (results.genre == null) {
  // No results.
  var err = new Error("Genre not found");
  err.status = 404;
  return next(err);
}
```


然后，此消息将传播给我们的错误处理代码（这是在我们生成应用程序框架时设置的 - 有关更多信息，请参阅处理错误）。

渲染的视图是 **genre\_detail**，它传递了该类型的标题`title`，种类`genre`和书本列表的变量（`genre_books`）。

视图
--

创建 **/views/genre\_detail.pug** ，并填写底下文字：


```js
extends layout

block content

  h1 Genre: #{genre.name}

  div(style='margin-left:20px;margin-top:20px')

    h4 Books

    dl
    each book in genre_books
      dt
        a(href=book.url) #{book.title}
      dd #{book.summary}

    else
      p This genre has no books
```


这个视图跟我们其他的模板非常相似。主要的差别在于，我们不使用 `title` 传送第一个标题 (虽然它还是用在底层的 **layout.pug** 模板，设定页面的标题)。

它看起來像是？
-------

运行本应用，并打开浏览器访问 http://localhost:3000/。选择 All genres 连结，然后选择其中一个种类 (例如，"Fantasy")。如果每样东西都设定正确了，你的页面看起来应该像底下的截图。

![Genre Detail Page - Express Local Library site](/zh-CN/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Genre_detail_page/locallibary_express_genre_detail.png)

**备注：** 你可能会收到与此类似的错误：


```bash
Cast to ObjectId failed for value " 59347139895ea23f9430ecbb" at path "\_id" for model "Genre"
```


这是来自 **req.params.id** 的 mongoose 错误。要解决这个问题，首先需要在 **genreController.js** 页面上要求 mongoose，如下所示：


```js
var mongoose = require("mongoose");
```


然后使用 \*\*mongoose.Types.ObjectId()\*\*将 id 转换为可以使用的。例如：


```js
exports.genre\_detail = function(req, res, next) {
    var id = mongoose.Types.ObjectId(req.params.id);
    ...
```


下一步
---

* 回到 Express 教程 5: 呈现图书馆数据
* 继续教程 5 下一个部分：书本细节页面
Django Tutorial: The Local Library website
==========================================

* 上一页
* Overview: Django
* 下一页

我们实战教程系列的第一篇教程会解释你将学到什么。并提供一个“本地图书馆”的例子作为概述。在接下来的教程里，我们会不断完善和改进这个网站。

|  |  |
| --- | --- |
| 前提： | 
 阅读
 Django 介绍。在接下来的文章里你需要
 创建 Django 开发环境.
  |
| 目标： | 介绍教程里使用的网站应用，让读者明白要讨论的主题。 |

概述
--

欢迎来到 MDN 的”本地图书馆“Django 教程。在教程里，我们会开发一个网站，用来管理本地图书馆的目录。

在这一系列的教程里你将：

* 运用 Django 的工具创建网站和应用的框架。
* 启动和停止开发用的服务器。
* 创建模型（models）用来代表应用里的数据。
* 运用 Django 的 admin 站点填充网站数据。
* 面对不同的网络请求，创建视图函数（views）取回相应的数据。并把数据用模板（templates）渲染成 HTML 展示在浏览器里。
* 创建网络分发器，将不同的 URL 模式分发给特定的视图函数（views）。
* 添加用户认证和会话（sessions）管理网站行为和进入权限。
* 使用表单。
* 为应用编写测试。
* 有效运用 Django 的安全系统。
* 把应用布置到生产环境中。

关于这些主题，你已经学会了一些，并对其他的也有了简单的了解。在这系列教程的最后，你会学到足够多而可以自己开发简单的 Django 应用了。

本地图书馆网站
-------

*本地图书馆*是我们在本系列教程里创建和不断改善的网站。跟你期望的一样，这个网站的目标是为一个小型的图书馆提供一个在线的目录。在这个小型图书管里，用户能浏览书籍和管理他们的账户。

这个例子是精心挑选出来的，因为它可以根据我们的需要增加或多或少的细节。也能用来展示几乎所有的 Django 特性。更重要的是，它提供了一条指南式的路线，在这条路线中，我们会用到 Django 网络框架最重要的功能：

* 在第一篇教程里，我们会定义一个简单到只能浏览的图书馆。图书馆的会员可以查找哪些书可以借阅。我们得以探索那些几乎所有网站都会运用的操作：阅读和展示数据库里的内容。
* 接下来，图书馆会慢慢扩展来展示更高级的 Django 特性。例如，我们会扩展功能，让会员能够保留图书。这个特性会展示如何使用表单，并支持用户认证。

尽管这是一个非常容易扩展的例子，它被称为本地图书馆是有原因的——我们希望用最少的信息帮助你快速创建和运用 Django。最后，我们会存储图书信息，图书数量，作者和其他重要信息。我们不会存储图书馆可能会存储的其他信息，或是提供一个支持多个图书馆或是”大型图书馆“功能的构建。

我卡住了，从哪里获得源代码呢？
---------------

在学习本系列教程时，我们会提供合适的代码片段，你可以粘贴复制，但是有些代码我们希望你能自己扩展（在提示下）。

如果你卡在某个地方，你可以在Github里找到网站的完整代码。I

总结
--

现在你对本地图书馆网站有了一些了解并知道你会学到什么。是时候创建我们例子会用到的网站框架了。

* 上一页
* Overview: Django
* 下一页
HTML 简介
=======

就其核心而言，HTML 是一种相当简单的、由不同元素组成的标记语言，它可以被应用于文本片段，使文本在文档中具有不同的含义（它是段落吗？它是项目列表吗？它是表格吗？），将文档结构化为逻辑块（文档是否有头部？有三列内容？有一个导航菜单？），并且可以将图片，影像等内容嵌入到页面中。本模块将介绍前两个用途，并且介绍一些 HTML 的基本概念和语法。

前言
--

尽管你无需事先拥有任何 HTML 相关知识以学习该模块，你仍至少需要熟悉一些使用电脑的基础知识，并会被动地使用网络（也就是看着它，浏览内容）。你需要配置基础的开发环境（详细说明请参见安装基本软件页面），并且懂得如何创建和管理文件（在处理文件页面中有详细说明）——它们都是我们纯新手 Web 开发入门模块的一部分。

**备注：** 如果你正在一台你不能创建文件的设备上作业，那么你需要在在线编程工具上运行（大多数）代码示例，如 JSBin 或 Glitch 等。

指南
--

本模块包含以下文章，它们将带你了解 HTML 的所有基本理论，并为你提供充分的机会来测试一些技能。

HTML 入门

涵盖了 HTML 绝对基础知识以帮助你入门——定义元素、属性和其他重要术语，并展示了它们在语言中的位置。我们还展示了一个典型的 HTML 页面的结构和一个 HTML 元素的结构，并解释了一些重要的基本语言特征。一路下来，我们会与 HTML 一起玩耍，以激发你的兴趣！

head 标签中有什么？HTML 中的元数据

当页面被加载后，HTML 中的 head 部分**是不会**被显示在 Web 浏览器中的。它包含了许多信息，例如网页的标题 `<title>`，指向 CSS 的链接（如果你使用 CSS 来设计 HTML 内容的样式的话），指向自定义网站图标的链接和一些元数据（关于 HTML 本身的数据，例如它的作者和描述这个文档的关键字）。

HTML 文本处理基础

HTML 的主要工作之一就是给予文本意义（也被叫做语义），以让浏览器知道如何正确的显示文本。这篇文章关注于如何用 HTML 将文本块分解为结构化的标题和段落、强调和加粗单词、创建列表以及其他内容。

创建超链接

超链接真的很重要——它们是“web”的意义所在。本文展示了创建超链接所需的语法，并讨论了创建超链接的最佳做法。

高级文本排版

HTML 中还有许多没有在 HTML 文本处理基础页面中提到的其他元素可以用于排版文本。这里的元素不太为人所知，但了解这些元素仍然很有用。在这篇文章里，你将学习如何标记引文、描述列表、计算机代码和其他类似的文本、下标和上标、联系信息等。

文档和网站结构

除了定义页面的个别部分（例如“段落”或“图像”）外，HTML 也被用于定义网站的区域（例如“标题”、“导航菜单”和“主要内容”）。本文将探讨如何规划一个基本的网站结构，以及如何编写 HTML 来表示这个结构。

调试 HTML

光是编写 HTML 还好，但如果出了什么问题，而你找不到问题的来源怎么办？本文将介绍一些可以帮上忙的工具。

测验
--

以下测验将测试你对上述指南中 HTML 基础知识的理解程度。

标记信件

我们迟早都要学会如何写信，而这也对测试我们的排版技能很有用！在这个测验中，你需要标记一封信。

结构化页面内容

此测验将测试你能否使用 HTML 构建简单的内容页面，其中包含页眉、页脚、导航菜单、主要内容和侧边栏。
使用 HTML 解决常见问题
==============

下面的链接指向日常中需要用 HTML 解决的问题的解决方案。

### 基本结构

HTML 应用最基础的是文档结构。如果你是 HTML 新手那么你应该和我们一起从这里开始学习。

* 如何创建 HTML 文档
* 如何将网页分成有逻辑的部分
* 如何设置一个适当的标题和段落结构
### 基本文本语义

HTML 专门为文档提供语义信息，因此，HTML 能够解答关于如何在文档中最好地传递消息的许多问题。

* 如何用 HTML 创建列表项
* 如何强调或凸显内容
* 如何表明文本是重要的
* 如何用 HTML 展示计算机代码
* 如何注释图片和图标
* 如何注解缩略语并使其可理解
* 如何为网页添加引述和引用
* 如何用 HTML 定义术语 (en-US)
### 超链接

使用 HTML 的主要原因之一，就是可以使用超链接来轻松导航，实现方式有以下几种：

* 如何创建超链接
* 如何创建导航菜单
### 图像 & 多媒体

* 如何在页面中添加图片
* 如何在页面中添加视频
### 脚本 & 样式

HTML 仅仅建立了文档结构。为解决演示问题，可使用 CSS 或脚本使页面具有交互功能。

* 如何在网页中使用 CSS
* 如何在网页中使用 JavaScript (en-US)
### 嵌入内容

* 如何在网页中嵌入另一个页面
不常见或进阶的问题
---------

除了基本问题，HTML 还有更丰富的功能，其提供了高级特性用于解决复杂问题。这些文章可以帮助你解决一些相对不常见的问题：

### 表单

表单是一种复杂的 HTML 结构，用于从网页向网络服务器发送数据。我们鼓励你仔细阅读完整指南。你可由此入门：

* 如何创建一个简单的网页表单
* 如何组织一个网页表单
### 表格信息

一些表格化信息/数据需用行和列整合到表格中去。而表格是最复杂的 HTML 结构之一，熟练掌握它并不容易：

* 如何创建一张数据表格
* 如何使 HTML 表格更具无障碍性
### 数据表示

* 如何用 HTML 表示数值和代码，参见上标和下标以及展示计算机代码
* 如何使用 data 属性
### 高级文本语义

* 如何控制 HTML 换行
* 如何标记内容的更改（文字的增加或删除）——参见 `<ins>` 与 `<del>` 元素。
### 高级图像 & 多媒体

* 如何为网页添加响应式图像
* 如何为网页添加矢量图像
* 如何在图像上添加 hit map
### 国际化

HTML 支持多语言，其提供了用于解决常见的国际化问题的工具。

* 如何为单一网页添加多语言支持
* 如何用 HTML 展现时间和日期
### 性能

* 如何写一个加载速度很快的 HTML 页面
多媒体与嵌入
======

在这份教程中，到目前为止我们已经看到了许多的文字了。但是网页除了文本之外什么都没有，真的非常无聊，所以，让我们开始看看怎样用更多有趣的内容让网页动起来！本模块要探索怎样用 HTML 来让你的网页包含多媒体，包括可以包含图像的不同方式，以及怎样嵌入视频，甚至是整个其他的网页。

#### 想要成为一名前端工程师？

我们汇总了一门课程，其中包含你实现成为前端工程师目标所需要的所有基本信息。

**从这儿开始**

预备知识
----

在你开始本模块之前，你应该已经拥掌握了关于 HTML 的基础知识，就是之前在HTML 简介中所述内容。如果你还没有看过那个模块（或者类似的），先去看看，然后再回来吧！

**备注：** 如果你正在一台你不能创建文件的设备上作业，那么你需要在在线编程工具上运行（大多数）代码示例，如 JSBin 或 Glitch 等。

指南
--

本模块包含以下的文章，你会了解到所有在网页上关于嵌入多媒体的基础知识。

HTML 中的图片

有一些其他类型的多媒体要考虑，但是从简单的 `<img>` 元素开始是符合逻辑的，它常常被用来在网页中嵌入一个简单的图片。在这篇文章中，我们要看看怎样更深入的使用它，包括基础知识，使用 `<figure>` 来为图片增加说明，以及怎样把它关联到 CSS 背景图片。

视频和音频内容

接下来，我们将看看怎样在我们的页面上用 HTML5 的 `<video>` 和`<audio>` 元素来嵌入视频和音频；包括基础知识，向不同的浏览器提供不同文件格式的访问方式，增加标题和副标题，以及增加对过时的浏览器的兼容。

从 <object> 到 <iframe>——其他嵌入技术

在这一节，我们将来了解一些另辟蹊径的内容，看一组元素，它们可以让你在页面中嵌入许多不同类型的内容： `<iframe>`、`<embed>` 和 `<object>` 元素。`<iframe>` 用来嵌入其他网页，而另外两者可以帮助你嵌入外部资源（例如 PDF 文件）。

在页面中添加矢量图像

矢量图像在一些特定场景中非常有用。不同于常见的格式，比如 PNG/JPG, 它们不会在放大的时候变得扭曲或者显示出像素格——它们可以在缩放时保持光滑。本文将为你介绍什么是矢量图像，以及如何在网页中添加流行的 SVG 格式图像。

响应式图片

现在有许多不同的设备类型能够浏览网络——从手机到台式电脑——在现代网络世界中掌握的一个基本概念就是响应式设计。这是指创建可以自动更改其功能以适应不同屏幕尺寸，分辨率等的网页。稍后将在 CSS 模块中详细介绍这一点，但是现在我们将看看 HTML 可用于创建响应式图像的工具，包括 `<picture>` 元素。

测验
--

以下测验将测试你对上述指南中涵盖的 HTML 基础知识的理解：

Mozilla 启动页面

在这个测验中，我们将测试你对本模块文章中讨论的一些技巧的了解，让你将一些图像和视频添加到一个关于 Mozilla 的时髦的页面！

参见
--

在图像的顶部添加一个点阵图

图像映射提供了一种机制，使图像的不同部分链接到不同的地方（想想地图，链接到有关你点击的每个不同国家的更多信息。）这种技术有时可能是有用的。

网络素质基础 2)

一个优秀的 Mozilla 基础课程，探讨并测试了多媒体和嵌入模块中谈到的一些技巧。深入了解撰写网页的基础知识，设计无障碍，共享资源，使用在线媒体和开放工作。
HTML 表格
=======

在 HTML 中一个很普通的任务是构建表格数据，有大量的元素和属性是来满足这种需求的。只需要一点儿的 CSS 来设定风格，HTML 让在 web 上显示表格数据变的很容易，例如你的学校的教学计划，你当地的游泳馆的时刻表，或者是关于你最爱的恐龙或足球队的统计数据。这个模块会教给你所有你需要知道的关于用 HTML 构建表格数据的知识。

#### 想要成为一名前端工程师？

我们汇总了一门课程，其中包含你实现成为前端工程师目标所需要的所有基本信息。

**从这儿开始**

预备知识
----

在你开始本模块之前，你应该已经掌握了关于 HTML 的基础知识，就是之前在 HTML 简介中所述内容。如果你还没有看过那个模块（或者类似的），先去看看，然后再回来吧！

**备注：** 如果你正在一台你不能创建文件的设备上作业，那么你需要在在线编程工具上运行（大多数）代码示例，如 JSBin 或 Glitch 等。

指南
--

本模块包含以下的文章，你将了解在 HTML 中创建表格的所有知识。

HTML 表格基础

本文将帮助你学习如何使用 HTML 格式，包括如行、列、表头、跨列的行或跨行的列等基本特性，以及如何将多行进行分组进行样式化。

HTML 表格高级功能与无障碍

在本模块第二篇文章中，我们将了解一些 HTML 表格的高级功能——比如表名称/表摘要，因为无障碍的原因，将表格内容划分为表头、主体以及脚部等章节。

测验
--

构造行星的数据结构

在表格的测验中，我们向你提供了一些在我们太阳系的行星的数据，不妨你把它构造成一个 HTML 的表格吧。
Mozilla 醒目页面
============

* 上一页
* Overview: Multimedia and embedding

在这个测验中，我们将测试你对于本模块文章所讨论的技术的掌握程度，让你将一些有关于 Mozilla 的图片和视频添加到一个漂亮的页面上！

|  |  |
| --- | --- |
| 前提： | 
 在开始这个测验之前，你应该了解了
 多媒体与嵌入
 模块的其他文章。
  |
| 目标： | 
 测试这些知识的掌握程度：在页面中嵌入图片和视频，框架，和 HTML
 响应式图片技术。
  |

起点
--

为了开始这次测验，你需要从 mdn-splash-page-start 这个 GitHub 目录下下载 HTML 和图片。保存在你本地设备上。

访问 originals 文件夹中不同的图片文件，然后用同样的方法将它们下载到本地。现在，你需要将这些图片文件保存到不同的目录下，因为在这些图片准备好被使用之前，你需要使用图像编辑器来处理这些图片。

**备注：** 这个示例的 HTML 文件包含一些页面的 CSS 样式。你不需要去碰 CSS 的内容，而只是 `<body>` 元素中的 HTML 部分，只要你插入了正确的标记，样式就会正确显示。

项目概要
----

在这个测验中，我们为你呈现了一个接近完成了的 Mozilla 醒目页面，旨在说明一些关于 Mozilla 的有趣的事情，以及提供一些更一步的资源链接。但目前还没有添加任何视频或图片，这份工作就交给你了！你需要添加一些图片、视频等多媒体元素，好让页面变得更漂亮和更有意义。下一小节详细描述了你需要做的工作：

### 准备图片

使用你最爱的图片编辑器，创建下面几张图片的 400px 宽的版本和 120px 宽的版本：

* `firefox_logo-only_RGB.png`
* `firefox-addons.jpg`
* `mozilla-dinosaur-head.png`

给它们取个有意义的名字，例如`firefoxlogo400.png` 和`firefoxlogo120.png`。

这些图片将和 `mdn.svg` 一起作为`further-info`区内资源链接的图标和网站页眉的火狐图标。将这些图片副本保存在与 `index.html`文件的同一个目录下。

接着，创建一个 1200px 宽的 `red-panda.jpg`风景图片版本，和一个 600px 宽的肖像版本，用来显示更近镜头下的熊猫。同样地，为它们取一个你可以轻松分辨出来的名字。将它们的副本保存在与 `index.html`文件相同的目录下。

**备注：** 你应该在看起来还行的前提下尽量优化 JPG 和 PNG 图片的大小，tinypng.com为此提供了很好的服务。

### 为 header 添加一个图标

在 `<header>` 元素中添加一个 `<img>` 元素，嵌入一个小尺寸版本的火狐图标。

### 为主 article 添加一个视频

就在 `<article>` 元素中（开放标签下面），嵌入一个 Bilibili 视频（https://www.bilibili.com/video/BV1rs411d7hC?p=2），使用 Bilibili 生成嵌入代码。视频的宽度应该是 400px。

### 为 further info 的链接添加响应式图片

在 `further-info` 类的 `<div>`里你会看到四个 `<a>` 元素，每个都指向一个有趣的、关于 Mozilla 的页面。为了完成这一部分，你需要在每个`<a>` 元素里插入一个 `<img>` 元素，需要包含合适的 `src`、`alt`、`srcset` 和 `sizes` 属性。

我们希望每张图片（除了某个本身就是响应式的）在浏览器的视口的宽度小于等于 480px 时使用的 120px 宽的图片，其他情况下选择 400px 的版本。

确保正确的链接匹配了正确的图片！

**备注：** 为了正确的测试 `srcset`/`sizes` 示例，你需要把你的网站上传到服务器（使用 Github pages 是一个简单免费的方法），访问服务器上的网页，你就可以使用浏览器开发者工具来测试它们是否正常工作，如 响应式图片：有用的开发工具中所说

### 一张小熊猫的艺术照

在`red-panda`类的`<div>` 中，我们希望插入一个`<picture>`元素，在视口宽度小于等于 600px 时使用那张比较小的纵向的熊猫图片，在其他情况下则使用大的横向的图片。

示例
--

下面的截图展示了在正确标记后，醒目页面在宽屏和窄屏下的样子。（可 在线查看）

![A wide shot of our example splash page](/zh-CN/docs/Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page/wide-shot.png)

![A narrow shot of our example splash page](/zh-CN/docs/Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page/narrow-shot.png)

评估
--

如果这个评估是一系列课程的一部分，你应该可以让你的老师或导师为你批改。如果你是自学，可以很容易地在 discussion thread about this exercise或Mozilla IRC的#mdn IRC 频道回复得到批改指南。请先自己试着做——作弊学不到任何东西！

* 上一页
* Overview: Multimedia and embedding