实时示例
MDN 支持在文章中显示代码块作为实时示例,使读者能够看到代码及其输出在网页上的显示效果。此功能使读者能够准确了解执行的代码将产生什么输出,使文档更加动态和具有指导意义。它还使作者能够完全确定文档中的代码块是否具有预期的输出,以及在与不同浏览器一起使用时是否能正常工作。
实时示例系统可以处理用 HTML、CSS 和 JavaScript 编写的代码块,无论它们在页面中的编写顺序如何。这确保了输出与组合的源代码相对应,因为系统直接在页面中运行代码。
与交互式示例不同,实时示例不提供用于捕获控制台日志记录或重置由用户输入更改的示例的内置支持。在示例部分中,展示了如何实现这些功能以及其他有用功能。
实时示例系统的工作原理是什么?
实时示例系统将代码块分组,将它们合并到 HTML 中,并在<iframe>
中呈现 HTML。实时示例包含两个部分
- 一个或多个分组在一起的代码块
- 一个宏调用,在
<iframe>
中显示组合代码块的结果
每个包含输出代码的代码块都有一个语言标识符 - html
、css
或 js
- 用于指定它是 HTML、CSS 还是 JavaScript 代码。语言标识符必须位于相应的代码块上,并且页面中必须存在一个宏调用 (EmbedLiveSample
) 以显示输出
## Examples
```html
<!-- HTML code -->
```
```css
/* CSS code */
```
{{EmbedLiveSample("Examples")}}
实时示例系统允许以不同的方式对代码块进行分组,以便有效地显示输出。下一部分将描述这些方法。
分组代码块
代码块可以通过两种方式进行分组
- 使用包含代码块的标题或块元素的 ID 作为标识符
- 为代码块指定一个字符串标识符
未明确指定标识符的代码块默认情况下使用包含代码块的标题或块元素的 ID 进行分组。在这种情况下,标识符是标题或块元素(例如<div>
)的 ID。以下示例展示了这种情况,其中块“样式化段落”内的 html
和 css
代码用于生成 EmbedLiveSample
宏调用的输出。
## 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 代码块分组在一起
## 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")}}
该宏使用包含 ID 的特殊 URL 来获取给定代码块组的输出。你永远不应该在内容中硬编码此 URL - 如果你需要链接到示例,请使用LiveSampleLink
宏。
生成的框架(或页面)是沙箱化的、安全的,并且在技术上可以执行 Web 上任何可行操作。当然,实际上,代码应该与页面的内容相关;任何不相关的材料都可能会被 MDN 的编辑社区删除。
实时示例系统提供了许多选项,我们将尝试逐个分析它们。
实时示例宏
可以使用两个宏来显示实时示例
EmbedLiveSample
将实时示例嵌入到页面中LiveSampleLink
创建一个链接,在新的页面中打开实时示例
在许多情况下,你可能只需添加少量工作即可将 EmbedLiveSample
或 LiveSampleLink
宏添加到页面中!只要可以使用标题的 ID 或带有 ID 的块来识别示例,添加宏即可完成任务。
EmbedLiveSample 宏
{{EmbedLiveSample(sample_id, width, height, screenshot_URL, page_slug, class_name, allow)}}
- sample_id
-
必填项:可以是示例的字符串标识符或用于绘制代码的标题或封闭块的 ID。要验证你是否具有正确的标题 ID,请查看页面目录中该部分的 URL;你还可以通过查看页面的源代码来检查它。
- width 已弃用
-
width
属性,用于<iframe>
,以px
为单位指定。自它不再有任何效果以来已弃用:实时示例始终跨越内容区域的整个宽度。 - height
-
height
属性,用于<iframe>
,以px
为单位指定。必须至少为60
。这是可选的;如果你省略它,将使用合理的默认高度。 - screenshot_URL 已弃用
-
一个屏幕截图的 URL,用于显示实时示例应该是什么样子。已弃用;只有在浏览器支持良好时才添加实时示例。
- page_slug 已弃用
-
包含示例的页面的标识符;这是可选的,如果未提供,则示例将从使用宏的同一页面中提取。已弃用;只有在代码位于同一页面上时才包含实时示例。
- class_name 已弃用
-
要应用于
<iframe>
的类名。已弃用;没有理由使用其他类名。 - allow
-
allow
属性,用于<iframe>
。这是可选的;默认情况下不存在允许的功能。
LiveSampleLink 宏
{{LiveSampleLink(block_ID, link_text)}}
使用实时示例系统
以下部分描述了一些实时示例系统的常见用例。
格式化实时示例
如果你在“示例”部分中编写了实时示例,请为此实时示例提供一个描述性的 H3 标题 (###
)。理想情况下,请编写一个简短的示例描述,解释场景以及你希望演示的内容。然后,按照以下 H4 标题 (####
) 列出的顺序添加子部分
- HTML
- CSS
- JavaScript
- 结果
在相应的子部分中编写代码块。
在**结果**子部分中,添加对 EmbedLiveSample
宏的调用。最好在此子部分中添加一些描述结果的文字。
如果你没有使用特定的语言类型(例如,如果你没有使用 JavaScript)或者如果你隐藏了代码块,则应省略相应的标题。
隐藏代码
有时候你只想显示与页面中呈现的示例相关的静态代码块。但是,您仍然需要 HTML、CSS 和 JavaScript 代码块来呈现这样的示例。
要实现这一点,您可以通过在语言标识符中添加 hidden
信息字符串来隐藏任何不相关的代码块。如果您这样做,请省略隐藏代码块的 ### HTML/CSS/JavaScript
标题。
使用上面的示例,但隐藏 HTML 代码,将如下所示
## 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 是块中包含的语言类型,例如 html
、css
或 js
。
注意:您可能为每种语言有多个块;它们将全部连接在一起。这使您可以拥有代码块,然后是对其工作原理的解释,然后是另一个代码块,等等。这使得制作包含实时示例和解释性文本的教程变得更加容易。
因此,请确保您的 HTML、CSS 和/或 JavaScript 代码的代码块都为该语言的语法突出显示配置正确,就可以了。
示例
本节包含示例,展示了实时示例系统如何使用,包括构成示例的代码块的不同分组方式以及如何在示例中显示日志输出。
请注意,代码块的标题(“HTML”、“CSS”或“JavaScript”)是大多数 MDN 示例中使用的约定,但实际上并非实时示例宏所必需。
按标题分组代码块
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 代码为该框以及其中的文本设置样式。
.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!”文本附加一个事件处理程序,以便在单击它时切换它。
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', 'Live sample demo link')}}
调用这些代码块产生的结果
按标识符分组代码块
此 HTML 创建一个段落和一些块,以帮助我们定位和设置消息的样式。live-sample___hello-world
字符串已添加到此代码块的 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
语言标识符中。
.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
语言标识符中。
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>
元素的大小。
<p>Just some simple text here.</p>
{{EmbedLiveSample("iframe_size", "", "60")}}
的结果
{{EmbedLiveSample("iframe_size", "", "120")}}
的结果
允许功能
allow
参数可用于指定包含实时示例输出的 <iframe>
元素中允许的功能。可用值来自 帧权限策略语法。
<div id="fullscreen-content">
<button id="toggle-btn">Toggle fullscreen</button>
</div>
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>
元素,用于显示日志输出。
<pre id="log"></pre>
JavaScript
接下来,定义日志记录函数 log()
。它将要记录的文本作为参数,并使用它来替换现有日志。
const logElement = document.querySelector("#log");
function log(text) {
logElement.innerText = text;
}
请注意,日志元素的内容是使用 innerText
属性设置的,这比使用 innerHTML
更安全,因为记录的文本不会解析为 HTML(这可能会潜在地注入恶意代码)。
CSS
CSS 设置日志记录元素的高度。
#log {
height: 20px;
}
日志记录测试代码
此示例旨在展示“如何记录”,因此“记录的内容”并不重要。因此,这被简单地实现为一个按钮,用户可以按下它来递增一个值。
<button id="increment" type="button">Press me many times</button>
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>
元素,用于显示日志输出。
<pre id="log"></pre>
JavaScript
接下来,定义日志记录函数 log()
。它将要记录的文本作为参数,并将其作为新行追加到日志元素中的内容。该函数还将元素的 scrollTop
设置为元素的 scrollHeight
,这会强制新行日志文本滚动到视图中。
const logElement = document.querySelector("#log");
function log(text) {
logElement.innerText = `${logElement.innerText}${text}\n`;
logElement.scrollTop = logElement.scrollHeight;
}
与前面的示例一样,我们使用 innerText
属性设置内容,因为这比使用 innerHTML
更不容易受到恶意代码的影响。
CSS
CSS 在元素内容溢出时添加滚动条,设置日志记录元素的高度,并添加边框。请注意,上面的 JavaScript 确保如果确实溢出,添加新的日志文本将使文本滚动到视图中。
#log {
height: 100px;
overflow: scroll;
padding: 0.5rem;
border: 1px solid black;
}
日志记录测试代码
此示例旨在展示“如何记录”,因此“记录的内容”并不重要。因此,这被简单地实现为一个按钮,用户可以按下它来递增一个值。
<button id="increment" type="button">Press me many times</button>
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 现在包含一个重置按钮。
<button id="increment" type="button">Press me many times</button>
<button id="reset" type="button">Reset</button>
<pre id="log"></pre>
JavaScript
该按钮的代码添加了一个 click
事件处理程序函数,该函数只是重新加载包含当前示例的框架。
const reload = document.querySelector("#reset");
reload.addEventListener("click", () => {
window.location.reload(true);
});
结果
多次单击“多次按下我”按钮。通过按下“重置”按钮来重置示例。
有关实时示例的约定
- 代码块的顺序
-
在添加实时示例时,应对代码块进行排序,使第一个代码块对应于此示例的主要语言(如果有)。例如,在为 HTML 参考添加实时示例时,第一个块应该是 HTML,在为 CSS 参考添加实时示例时,它应该是 CSS,依此类推。
- 标题的命名
-
在没有歧义的情况下(例如,示例位于“示例”部分下),标题应简单明了,只包含对应语言的名称:HTML、CSS、JavaScript、SVG 等(见上文)。不要使用“HTML 内容”或“JavaScript 内容”等标题。但是,如果这样的简短标题使内容不清楚,可以使用更具思考性的标题。
- 使用“结果”块
-
在不同的代码块之后,请在使用
EmbedLiveSample
宏之前使用最后一个“结果”块(见上文)。这样,示例的语义对读者和任何可能解析页面的工具(例如屏幕阅读器、网络爬虫)来说就更加清晰。