书籍中的章节名称、演讲中的引用、文章中的关键词、报告中的统计数据——所有这些都是可以隔离并转化为内容重要性的高级摘要的内容类型。
例如,您是否看到 Business Insider 在进入内容之前提供了文章的关键要点?

这就是我们要做的事情,但尝试使用 HTML Slot、HTML Template 和 Shadow DOM 直接从文章中提取要点。
这三个标题规范通常用作 Web Components 的一部分——完全功能的自定义元素模块,旨在在网页中重复使用。
现在,我们的目标是文本提取,它不需要自定义元素,但它可以利用这三种技术。
有一个更基本的方法可以做到这一点。 例如,我们可以提取文本并在页面上显示提取的文本,使用一些基本的脚本,*而无需*使用 slot 和 template。 那么,如果我们可以使用更熟悉的东西,为什么要使用它们呢?
原因是**使用这些技术允许我们在 HTML 中为提取的文本预设标记代码(可选地,样式或脚本)**。 我们在继续本文时会看到这一点。
现在,作为我们将使用技术的非常淡化的定义,我会说
- 模板是一组可以在页面中重复使用的标记。
- Slot 是页面中指定元素的占位符。
- Shadow DOM 是一个 DOM 树,在我们使用脚本添加它之前,它实际上不存在于页面上。
一旦我们开始编码,我们将更深入地了解它们。 现在,我们要做的是创建一篇包含文章关键点列表的文章。 而且,你可能已经猜到了,这些关键点是从文章文本中提取并汇集到关键点部分的。
查看 Pen
使用 HTML Slot 和 HTML Template 进行文本提取 by Preethi Sam (@rpsthecoder)
on CodePen.
关键点显示为一个列表,在要点之间有一个设计。 因此,让我们首先为该列表创建一个**模板**,并指定一个用于放置列表的位置。
<article><!-- Article content --></article>
<!-- Section where the extracted keypoints will be displayed -->
<section id='keyPointsSection'>
<h2>Key Points:</h2>
<ul><!-- Extracted key points will go in here --></ul>
</section>
<!-- Template for the key points list -->
<template id='keyPointsTemplate'>
<li><slot name='keyPoints'></slot></li>
<li style="text-align: center;">⤙—⤚</li>
</template>
我们得到的是一个语义化的 <section>
,其中包含一个 <ul>
,关键点列表将位于其中。 然后我们有一个 <template>
用于列表项,它包含两个 <li>
元素:一个带有 <slot>
占位符,用于来自文章的关键点,另一个带有居中的设计。
布局是任意的。 重要的是**在提取的关键点将要出现的位置放置一个 <slot>
**。 <template>
内部的任何内容都不会在页面上呈现,直到我们使用脚本将其添加到页面中。
此外,<template>
内部的标记可以使用内联样式或由 <style>
包含的 CSS 进行设置样式
<template id='keyPointsTemplate'>
<li><slot name='keyPoints'></slot></li>
<li style="text-align: center;">⤙—⤚</li>
<style>
li{/* Some style */}
</style>
</template>
有趣的部分! **让我们从文章中挑选关键点。** 注意 <template>
中 <slot>
的 name
属性的值(keyPoints
),因为我们需要它。
<article>
<h1>Bears</h1>
<p>Bears are carnivoran mammals of the family Ursidae. <span><span slot='keyPoints'>They are classified as caniforms, or doglike carnivorans</span></span>. Although only eight species of bears <!-- more content --> and partially in the Southern Hemisphere. <span><span slot='keyPoints'>Bears are found on the continents of North America, South America, Europe, and Asia</span></span>.<!-- more content --></p>
<p>While the polar bear is mostly carnivorous, <!-- more content -->. Bears use shelters, such as caves and logs, as their dens; <span><span slot='keyPoints'>Most species occupy their dens during the winter for a long period of hibernation</span></span>, up to 100 days.</p>
<!-- More paragraphs -->
</article>
关键点被包装在一个 <span>
中,它带有 slot
属性值(“keyPoints
”),与 <template>
中 <slot>
占位符的 name
相匹配。
还要注意,我在关键点之外添加了另一个 <span>
**。
原因是插槽名称通常是唯一的,并且不会重复,因为一个 <slot>
使用一个插槽名称匹配一个元素。 如果有多个带有相同插槽名称的元素,<slot>
占位符将被所有这些元素连续替换,最后以最后一个元素作为占位符中的最终内容。
所以,如果我们将 <template>
中的单个 <slot>
与段落或整篇文章中所有具有相同 slot
属性值的 <span>
元素(我们的关键点)匹配,我们将最终只在段落或文章中最后一个关键点出现在 <slot>
的位置。
这不是我们需要的。 我们需要显示所有关键点。 因此,我们用外部 <span>
包装关键点,以便将每个单独的关键点与 <slot>
分别匹配。 通过查看脚本,这更加明显,所以让我们这样做。
const keyPointsTemplate = document.querySelector('#keyPointsTemplate').content;
const keyPointsSection = document.querySelector('#keyPointsSection > ul');
/* Loop through elements with 'slot' attribute */
document.querySelectorAll('[slot]').forEach((slot)=>{
let span = slot.parentNode.cloneNode(true);
span.attachShadow({ mode: 'closed' }).appendChild(keyPointsTemplate.cloneNode(true));
keyPointsSection.appendChild(span);
});
首先,我们遍历每个带有 slot
属性的 <span>
并获取其父元素(外部 <span>
)的副本。 请注意,如果愿意,我们也可以直接遍历外部 <span>
,方法是为它们提供一个共同的 class
值。
然后,外部 <span>
副本被附加到一个阴影树 (span.attachShadow
),该阴影树由模板内容的克隆组成 (keyPointsTemplate.cloneNode(true)
).
这种“附加”导致模板列表项中的 <slot>
(在阴影树中)吸收带有匹配插槽名称的内部 <span>
,即我们的关键点。
然后,已插槽的关键点被添加到页面末尾的关键点部分 (keyPointsSection.appendChild(span)
)。
在循环过程中,所有关键点都会发生这种情况。
实际上就是这样。 我们已经从文章中获取了所有关键点,复制了它们,然后将副本放入列表模板中,以便所有关键点都组合在一起,提供文章的简明总结。
再次展示该演示
查看 Pen
使用 HTML Slot 和 HTML Template 进行文本提取 by Preethi Sam (@rpsthecoder)
on CodePen.
您如何看待这种技术? 这是否对长篇内容(如博客文章、新闻文章甚至维基百科条目)有用? 您能想到哪些其他用例?
这是一个有趣的想法。 我能看到它与 HTML
mark
元素一起使用,以突出显示文本中的关键点。(我甚至能看到一个交互式功能,允许读者突出显示他们认为是关键点的段落,然后在文章末尾显示这些段落,以便轻松参考和/或打印。)撇开概念不谈,我仍然不明白为什么你需要外部
span
。 由于您是通过 JavaScript 构建关键点列表,因此您可以克隆您想要的任何元素。document.querySelectorAll('[slot]')
将找到所有内部span
(带有“slot”属性的span
),您将克隆它们(一次一个),附加模板的克隆(我假设您可以根据需要克隆多次),然后将结果附加到ul
。 所以我想我不理解你关于命名插槽(我假设在模板中)通常被具有相同插槽名称的每个元素覆盖的陈述。 当我读到它时,我假设模板中的插槽是由浏览器的 HTML 引擎自动填充的,但这似乎并非如此,因为您使用 JavaScript 生成关键点列表。 你能解释一下我遗漏了什么吗?另一个值得注意的是:您似乎关心语义,但您正在将
li
元素用于纯粹的装饰目的。 出于可访问性原因*,您应该*至少*在这些“分隔符”li
上包含role="presentation"
,以便屏幕阅读器在宣布 (a) 列表中包含多少项和 (b) 列表项本身时不会包含它们。 更重要的是,完全消除它们并使用 CSS 来显示这些分隔符。(*我知道这篇文章不是专注于可访问性,但我认为在任何教程中展示最佳实践总是值得的——即使这些实践不是文章的主要重点。)
尽管如此,感谢您提供了一个新的技术让我探索!