实时示例(EmbedLiveSample)

MDN 支持在文章中将代码块显示为实时示例,这样读者可以同时看到源代码及其在网页上的输出。此功能使读者能够准确理解执行代码会产生什么效果,使文档更具动态性和教学意义。它还允许作者完全确定文档中的代码块具有预期的输出,并且在不同浏览器中使用时能正常工作。

实时示例系统可以处理用 HTML、CSS 和 JavaScript 编写的代码块,无论它们在页面中编写的顺序如何。这确保了输出与组合后的源代码相对应,因为系统直接在页面中运行代码。

交互式示例不同,实时示例不提供内置支持来捕获控制台日志或重置由用户输入更改的示例。 示例部分展示了如何实现这些以及其他有用的功能。

实时示例如何工作?

实时示例将代码块分组,将它们合并到 HTML 中,并在 <iframe> 中渲染 HTML。一个实时示例由两部分组成:

  • 一个或多个组合在一起的代码块
  • 一个宏调用,在 <iframe> 中显示代码块的结果

每个包含输出代码的代码块都有一个语言标识符——htmlcssjs——用于指定它是 HTML、CSS 还是 JavaScript 代码。语言标识符必须在相应的代码块上,并且页面中必须存在宏调用(EmbedLiveSample)才能显示输出。

md
## Examples

```html
<!-- HTML code -->
```

```css
/* CSS code */
```

{{EmbedLiveSample("Examples")}}

实时示例系统允许以不同方式对代码块进行分组,以有效地显示输出。下一节将描述这些方法。

分组代码块

代码块可以通过两种方式分组:

  1. 使用包含代码块的标题或块元素的 ID 作为标识符
  2. 指定一个字符串标识符以及代码块

默认情况下,未明确指定标识符的代码块将使用包含代码块的标题或块元素的 ID 进行分组。在这种情况下,标识符是标题或块元素(例如 <div>)的 ID。这在下面的示例中显示,其中“段落样式”块中的 htmlcss 代码用于生成 EmbedLiveSample 宏调用的输出。

md
## Examples

### Styling a paragraph

In this example, we're using CSS to style paragraphs that have the `fancy` class set.

#### HTML

```html
<p>I'm not fancy.</p>

<p class="fancy">But I am!</p>
```

#### CSS

```css
p.fancy {
  color: red;
}
```

#### Result

{{EmbedLiveSample("Styling a paragraph")}}

Only the `<p>` element with `class="fancy"` will get styled `red`.
  • 如果 ID 属于块元素,则该组包含使用其 ID 的封闭块元素内的所有代码块。
  • 如果 ID 属于某个标题,则该组包含该标题之后且在同一标题级别的下一个标题之前的所有代码块。请注意,指定标题的子标题下的代码块都将使用;如果这不是您想要的效果,请使用块元素上的 ID 或使用字符串标识符。

要使用标识符对代码块进行分组,请在代码块的信息字符串中添加格式为 live-sample___{IDENTIFIER} 的字符串。标识符必须是您要分组的代码块的唯一标识符。例如,live-sample___color-picker 使用 color-picker 作为实时示例系统的标识符,并且所有信息字符串中包含 live-sample___color-picker 的代码块都将在实时示例中合并。以下示例使用标识符 color-picker 将 CSS 和 JavaScript 代码块组合在一起。

md
## Examples

### Styling a paragraph

In this example, we're using CSS to style paragraphs that have the `fancy` class set.

```html live-sample___paragraph-styling
<p>I'm not fancy.</p>

<p class="fancy">But I am!</p>
```

```css live-sample___paragraph-styling
p.fancy {
  color: red;
}
```

Only the `<p>` element with `class="fancy"` will get styled `red`:

{{EmbedLiveSample("paragraph-styling")}}

该宏使用一个特殊的 URL,其中包含 ID 以获取给定代码块组的输出。您不应在内容中硬编码此 URL——如果您需要链接到示例,请使用 LiveSampleLink 宏。

生成的框架(或页面)是沙盒化的,安全的,并且技术上可以做任何在网络上可行的事情。当然,实际上,代码应该与页面内容相关;任何无关材料都可能被 MDN 的编辑社区删除。

实时示例系统有很多可用的选项,我们将尝试逐一分解它们。

实时示例宏

您可以使用两个宏来显示实时示例:

在许多情况下,您可能只需很少或无需额外工作即可将 EmbedLiveSampleLiveSampleLink 宏添加到页面!只要示例可以通过标题的 ID 识别,或者位于具有可用 ID 的块中,添加宏即可完成任务。

EmbedLiveSample 宏

{{EmbedLiveSample(sample_id, width, height, screenshot_URL, page_slug, class_name, allow, sandbox)}}
sample_id

必填:这可以是示例的字符串标识符,也可以是用于提取代码的标题或封闭块的 ID。要验证您是否具有正确的标题 ID,请查看页面目录中该部分的 URL;您也可以通过查看页面源代码进行检查。

width 已弃用

<iframe>width 属性,以 px 为单位指定。已废弃,因为它不再有任何作用:实时示例总是跨内容区域的整个宽度。

height

<iframe>height 属性,以 px 为单位指定。必须至少为 60。这是可选的;如果省略,将使用合理的默认高度。

screenshot_URL 已废弃

显示实时示例应有的外观的屏幕截图的 URL。已废弃;仅在有合理的浏览器支持时才添加实时示例。

page_slug 已废弃

包含示例的页面的 slug;这是可选的,如果未提供,则从使用宏的同一页面中提取示例。已废弃;仅当代码在同一页面上时才包含实时示例。

class_name 已废弃

要应用于 <iframe> 的类名。已废弃;没有理由使用其他类名。

allow

<iframe>allow 属性。这是可选的;默认情况下不包含任何允许的功能。

sandbox

一个字符串,包含示例应包含的 sandbox 属性。允许的值有 allow-modalsallow-formsallow-popups。可以提供多个值,例如 "allow-modals allow-popups"

{{LiveSampleLink(block_ID, link_text)}}
block_ID

要从中提取代码的标题或封闭块的 ID。确保 ID 正确的最佳方法是查看页面目录中该部分的 URL;您也可以通过查看页面源代码进行检查。

用作链接文本的字符串。

使用实时示例系统

以下部分描述了实时示例系统的几个常见用例。

格式化实时示例

如果您在“示例”部分编写实时示例,请为该实时示例提供描述性的 H3 标题(###)。理想情况下,编写一个简短的示例描述,解释场景以及您希望演示的内容。然后按照以下列出的顺序添加带有 H4 标题(####)的子部分:

  • HTML
  • CSS
  • JavaScript
  • 结果

在上面列出的相应子部分中编写代码块。

结果子部分中,添加对 EmbedLiveSample 宏的调用。最好在该子部分中包含一些额外的散文来描述结果。

如果您不使用特定的语言类型(例如,如果您不使用 JavaScript)或者您正在隐藏代码块,那么您应该省略相应的标题。

隐藏代码

有时您只想显示与页面中渲染的示例相关的静态代码块。但是,您仍然需要 HTML、CSS 和 JavaScript 代码块来渲染这样的示例。

要实现此目的,您可以通过向语言标识符添加 hidden 信息字符串来隐藏任何不相关的代码块。如果您这样做,请省略隐藏代码块的 ### HTML/CSS/JavaScript 标题。

使用上面的示例,但隐藏 HTML 代码将如下所示:

md
## Examples

### Styling a paragraph

In this example, we're using CSS to style paragraphs that have the `fancy` class set.

```html hidden
<p>I'm not fancy.</p>

<p class="fancy">But I am!</p>
```

#### CSS

```css
p.fancy {
  color: red;
}
```

#### Result

Only the `<p>` element with `class="fancy"` will get styled `red`.

{{EmbedLiveSample("Styling a paragraph")}}

将片段转换为实时示例

一个常见的用例是将 MDN 上已有的现有代码片段转换为实时示例。第一步是添加代码片段或确保现有代码片段在内容和标记方面都已准备好用作实时示例。这些代码片段必须共同组成一个完整、可运行的示例。例如,如果现有片段只显示 CSS,您可能需要添加一个 HTML 片段供 CSS 操作。

每段代码必须位于一个代码块中,每种语言一个单独的块,并正确标记其语言类型。大多数情况下,这已经完成,但始终值得仔细检查以确保每段代码都配置了正确的语法。这是通过在代码块上使用 language-type 语言标识符来完成的,其中 language-type 是块包含的语言类型,例如 htmlcssjs

注意:每种语言可以有多个块;它们都被连接在一起。这允许您有一段代码,然后是对其工作原理的解释,然后是另一段代码,依此类推。这使得制作利用穿插有解释性文本的实时示例的教程等内容变得更加容易。

因此,请确保您的 HTML、CSS 和/或 JavaScript 代码块都已正确配置其语言的语法高亮显示,然后您就可以开始了。

示例

本节包含示例,展示了如何使用实时示例系统,包括对组成示例的代码块进行分组的不同方式,以及如何在示例中显示日志输出。

请注意,代码块的标题(“HTML”、“CSS”或“JavaScript”)在大多数 MDN 示例中都是约定俗成的用法,但实际上并非实时示例宏所必需。

按标题分组代码块

HTML

此 HTML 创建一个段落和一些块,以帮助我们定位和设置消息的样式。

html
<p>A simple example of the live sample system in action.</p>
<div class="box">
  <div id="item">Hello world! Welcome to MDN</div>
</div>

CSS

CSS 代码设置框的样式以及其中的文本。

css
.box {
  width: 200px;
  border-radius: 6px;
  padding: 20px;
  background-color: #ffaabb;
}

#item {
  font-weight: bold;
  text-align: center;
  font-family: sans-serif;
  font-size: 1.5em;
}

JavaScript

在 JavaScript 示例中,我们向“Hello world!”文本附加了一个事件处理程序,当点击时会切换它。

js
const el = document.getElementById("item");
let toggleClick = false;
el.onclick = function () {
  this.textContent = toggleClick
    ? "Hello world! Welcome to MDN"
    : "Owww, stop poking me!";
  toggleClick = !toggleClick;
};

结果

这是通过 {{EmbedLiveSample('grouping_code_blocks_by_heading')}} 运行以上代码块的结果

这是通过 {{LiveSampleLink('grouping_code_blocks_by_heading', '实时示例演示链接')}} 调用这些代码块生成的链接

实时示例演示链接

按标识符分组代码块

此 HTML 创建一个段落和一些块,以帮助我们定位和设置消息的样式。字符串 live-sample___hello-world 已添加到此代码块的 html 语言标识符中。

html
<p>A simple example of the live sample system in action.</p>
<div class="box">
  <div id="item">Hello world! Welcome to MDN</div>
</div>

CSS 代码设置框的样式以及其中的文本。字符串 live-sample___hello-world 已添加到此代码块的 css 语言标识符中。

css
.box {
  width: 200px;
  border-radius: 6px;
  padding: 20px;
  background-color: #ffaabb;
}

#item {
  font-weight: bold;
  text-align: center;
  font-family: sans-serif;
  font-size: 1.5em;
}

此 JavaScript 代码向“Hello world!”文本附加了一个事件处理程序,当点击时会切换它。字符串 live-sample___hello-world 也已添加到此代码块的 js 语言标识符中。

js
const el = document.getElementById("item");
let toggleClick = false;
el.onclick = function () {
  this.textContent = toggleClick
    ? "Hello world! Welcome to MDN"
    : "Owww, stop poking me!";
  toggleClick = !toggleClick;
};

我们通过在 {{EmbedLiveSample('hello-world')}} 宏调用中使用字符串标识符 hello-world 运行以上代码块获得此输出

显示特定大小的 <iframe>

使用 height 参数指定包含实时示例输出的 <iframe> 元素的大小。

html
<p>Just some simple text here.</p>

{{EmbedLiveSample("iframe_size", "", "60")}} 的结果

{{EmbedLiveSample("iframe_size", "", "120")}} 的结果

允许的功能

allow 参数可用于指定包含实时示例输出的 <iframe> 元素中允许的功能。可用值来自框架的权限策略语法

html
<div id="fullscreen-content">
  <button id="toggle-btn">Toggle fullscreen</button>
</div>
js
const toggleBtn = document.getElementById("toggle-btn");
const fullscreenContent = document.getElementById("fullscreen-content");

toggleBtn.addEventListener("click", () => {
  if (document.fullscreenElement) {
    document.exitFullscreen();
  } else {
    fullscreenContent.requestFullscreen();
  }
});

{{EmbedLiveSample("allowing_features", "", "60", "", "", "", "fullscreen")}} 的结果

{{EmbedLiveSample("allowing_features", "", "60")}} 的结果

显示单条日志

此示例展示了如何在实时示例中实现简单的单条日志,每次添加新的日志条目时,都会替换先前的值。

为了清晰起见,此示例将日志代码和使用它的代码分开,并首先显示日志代码。通常,在实现自己的示例时,应将日志元素放置在其他 UI 元素下方。

注意:将日志输出作为示例的一部分显示比使用 console.log() 提供更好的用户体验。

HTML

创建一个 id"log"<pre> 元素,用于显示日志输出。

html
<pre id="log"></pre>

JavaScript

接下来定义日志函数 log()。它以要记录的文本作为参数,并用它替换现有日志。

js
const logElement = document.querySelector("#log");
function log(text) {
  logElement.innerText = text;
}

请注意,日志元素的内容是使用 innerText 属性设置的,这比使用 innerHTML 更安全,因为记录的文本不会被解析为 HTML(这可能会注入恶意代码)。

CSS

CSS 设置日志元素的高度。

css
#log {
  height: 20px;
}

日志测试代码

此示例旨在展示“如何记录”,因此“记录什么”并不那么重要。因此,它被简单地实现为一个按钮,用户可以按下该按钮来增加值。

html
<button id="increment" type="button">Press me many times</button>
js
const incrementButton = document.querySelector("#increment");
let incrementValue = 0;
incrementButton.addEventListener("click", () => {
  incrementValue++;
  log(`The button has been pressed ${incrementValue} time(s)`);
});

结果

按下按钮以添加新的日志内容。

显示追加项目的日志

此示例展示了如何在实时示例中实现一个简单的“日志控制台”。每次添加日志时,控制台都会在输出末尾追加新行,并将新项目滚动到视图中。

为了清晰起见,此示例将日志代码和使用它的代码分开,并首先显示日志代码。通常,在实现自己的示例时,应将日志元素放置在其他 UI 元素下方。

注意:将日志输出作为示例的一部分显示比使用 console.log() 提供更好的用户体验。

有关更完整的示例,请参阅 DataTransfer.effectAllowed

HTML

创建一个 id"log"<pre> 元素,用于显示日志输出。

html
<pre id="log"></pre>

JavaScript

接下来定义日志函数 log()。它以要记录的文本作为参数,并将其作为新行追加到日志元素中的内容。该函数还将元素 scrollTop 设置为元素的 scrollHeight,这会强制将新行日志文本滚动到视图中。

js
const logElement = document.querySelector("#log");
function log(text) {
  logElement.innerText = `${logElement.innerText}${text}\n`;
  logElement.scrollTop = logElement.scrollHeight;
}

与上一个示例一样,我们使用 innerText 属性设置内容,因为这比使用 innerHTML 更不容易受到恶意代码的影响。

CSS

CSS 在元素内容溢出时添加滚动条,设置日志元素的高度,并添加边框。请注意,上面的 JavaScript 确保如果溢出,添加新的日志文本将使文本滚动到视图中。

css
#log {
  height: 100px;
  overflow: scroll;
  padding: 0.5rem;
  border: 1px solid black;
}

日志测试代码

此示例旨在展示“如何记录”,因此“记录什么”并不那么重要。因此,它被简单地实现为一个按钮,用户可以按下该按钮来增加值。

html
<button id="increment" type="button">Press me many times</button>
js
const incrementButton = document.querySelector("#increment");
let incrementValue = 0;
incrementButton.addEventListener("click", () => {
  incrementValue++;
  log(`The button has been pressed ${incrementValue} time(s)`);
});

结果

按下按钮以添加新的日志内容。

显示重置按钮

重置按钮对于无法在不重置页面的情况下恢复到初始状态的示例很有帮助。例如,Highlight.priority“设置优先级”示例需要一个重置按钮,因为一旦您设置了任一优先级,初始状态就不可用了。

此示例展示了如何向上面显示追加项目的日志示例添加重置按钮。请注意,日志代码的 JavaScript 和 CSS 与上一个示例相同,因此该代码是隐藏的。

HTML

示例的 HTML 现在包含一个重置按钮。

html
<button id="increment" type="button">Press me many times</button>
<button id="reset" type="button">Reset</button>
<pre id="log"></pre>

JavaScript

按钮的代码添加了一个 click 事件处理函数,该函数只是重新加载包含当前示例的框架。

js
const reload = document.querySelector("#reset");

reload.addEventListener("click", () => {
  window.location.reload(true);
});

结果

多次点击“多次按下我”按钮。通过按下“重置”按钮重置示例。

关于实时示例的约定

代码块的顺序

添加实时示例时,代码块应排序,以便第一个代码块对应于此示例的主要语言(如果存在)。例如,为 HTML 参考添加实时示例时,第一个块应为 HTML;为 CSS 参考添加实时示例时,应为 CSS,依此类推。

标题命名

当没有歧义时(例如,示例在“示例”部分下),标题应直接使用相应语言的名称:HTML、CSS、JavaScript、SVG 等(见上文)。不应使用“HTML 内容”或“JavaScript 内容”之类的标题。但是,如果这样的短标题使内容不清楚,则可以使用更周到的标题。

使用“结果”块

在不同的代码块之后,请在使用 EmbedLiveSample 宏之前使用最后一个“结果”块(见上文)。这样,示例的语义对于读者和任何解析页面的工具(例如,屏幕阅读器、网络爬虫)都更加清晰。