原文链接:utilitybend.com/blog/gettin...
2024年可能对 web components 来说是很重要的,并且我对此感到激动。实话实说------几个月前------我几乎对他们毫无了解,因为我认为她们就是网络上流行的小众事物。但是它们引起了很多轰动,所以我想要更了解他们,现在我可以骄傲的说我在 npm 上发布了我的第一个(无用的)Web组件- 情人节特别的 - 为爱元素。
有关 web components 的两个帖子
文章将会被分为两个部分,在第一个部分里,我想要去介绍一些 web components 的基础,而第二个部分将作为创造第一个 web component 的教程。
对那些对 web components 完全不了解的朋友------你不需要感到羞愧。我正在追赶自己,在这篇文章里,我想要深入研究相关理论和一些基本术语,直到几个月前,这些术语对我来说还是胡言乱语。我博客其中一个关键的元素就是记录我学习到的东西,并且希望其他人也可以从中获益。虽然关于这个课题可能有更好的和更深入的教程。接下来我会写一些基础知识并且会在本文末尾提供一些推荐读物。
如果你确实不关心这些基础知识,并且只想看看我写的组件,那很好。
web components 是什么?
我周末最喜欢的活动就是和我的女儿一起打开乐高经典并且简单的构建一些东西------有些遵循我的小册子,有些仅仅依靠我们的想象,当我们在乐高盒子里找碎片的时候,我们偶然发现有些碎片是连在一起的,使我们更容易避免一切从头开始。这是很棒的。你已经找到了一个可以轻松重用的组件。
这是一个介绍web component的完美的类比。他们就像构建网站甚至是构建块组的构建块
我很确定这个比喻已经被用过很多次了因为我之前在Google搜索看到了很多次,但是它对于解释 web components 是一个完美的例子所以我无耻的盗用了hhh(看看我在这做了什么?这个类比成为了一个 component)
让我们从行话开始:自定义元素
不是使用像 <div>
或者 <button>
这样的标准的 tag,而是可以设计像 <my-button>
或者 <for-love>
这样自己的 tag,这些 tags 代表了我们可以使用并且在我们的网站或App复用的独一无二的组件。这就好像你有自己的工具库去满足你的需求。自定义元素内部总是需要有一个连字符,以将它们与标准HTML元素区分开来,并遵循Web组件规范设置的命名约定。连字符背后的主要原因是为了避免冲突------减少与标准HTML元素命名冲突的机会。因为标准的HTML元素不包含连字符(当然现在也不会)。
Light and Shadow DOM
这是一开始对我来说有点复杂的地方,但这是我学习/想象它的最佳方式:
Shadow DOM就像一个隐藏的web元素的房间。假设你有一个工作空间,在那里你可以构建网站的不同部分。有些部分需要在不影响其他部分的情况下完成它们的工作。Shadow DOM提供了一个封装的空间来完成这一工作。这就像在一个特定的区域周围放一块透明的窗帘。这个"隐藏房间"中的元素可以有自己的样式、脚本和结构,而不会干扰主页或其他元素的样式和脚本。我们所指的其他元素就是我们所说的Light DOM。
我不记得我在哪里听到过透明窗帘的比喻,我没有发明它,但它一直困扰着我。还有这个简单的web组件示例,它有一个输出"this is content in the Shadow DOM":
html
<div>
<p>This is content outside the Shadow DOM, thus "Light DOM".</p>
<my-element></my-element>
</div>
<script>
// Create a new custom element
class MyElement extends HTMLElement {
constructor() {
super();
// Create a Shadow DOM for this custom element
const shadow = this.attachShadow({ mode: 'open' });
// Create a paragraph inside the Shadow DOM
const paragraph = document.createElement('p');
paragraph.textContent = 'This is content inside the Shadow DOM.';
// Append the paragraph to the Shadow DOM
shadow.appendChild(paragraph);
}
}
// Define our custom element
customElements.define('my-element', MyElement);
</script>
Shadow DOM具有一些非常具体的特性:
封装性
在ShadowDOM内部,您的样式和脚本不受外部世界的影响。此行为有助于防止您的样式意外干扰网页上的其他元素。除了自定义属性外,外部CSS不会对其产生任何影响。
组合性
Shadow DOM引入了插槽,即可以在其中滑动自己的内容的小占位符。这意味着您可以自定义元素的内部,而不会干扰原始设计。这是如此强大,让我告诉你为什么:
在下面的示例中,我们将在web组件内部插入<h2>
和<p>
它唯一能做的就是在它们之间放置一个<hr>(我知道,这不是你会使用web组件的事情,但这是一个简单的例子)。
html
<my-card>
<!-- Content placed inside the slots -->
<h2 slot="title">Card Title</h2>
<p slot="content">This is the content of the card.</p>
</my-card>
<script>
class MyCard extends HTMLElement {
constructor() {
super();
// Create a Shadow DOM for this custom element
const shadow = this.attachShadow({ mode: 'open' });
// Create a container for the card content
const cardContainer = document.createElement('div');
// Create slots for title and content place hr between them
cardContainer.innerHTML = `
<slot name="title"></slot>
<hr>
<slot name="content"></slot>
`;
// Append the card container to the Shadow DOM
shadow.appendChild(cardContainer);
}
}
customElements.define('my-card', MyCard);
</script>
可访问性
辅助功能是一种共享语言。Shadow DOM内部的元素可以理解和使用与外部元素相同的可访问性语言。更重要的是,它确实可以在一些更难访问的用例(如选项卡)中帮助我们。可以在genericcomponents中找到一个很好的web组件集合。
关注点分离
ShadowDOM使您能够将结构、样式和行为整齐地排列在各自的隔间中。想象一下,有一个web组件库,用于所有这些重复的任务:可访问的选项卡、图像缩放和可设置动画的下拉菜单。我们仍然可以使用自定义属性进行样式设置,因为这些属性会渗透到web组件中。但是,如果我们想做一些严肃的主题化,并想创建灵活的web组件,下一个可能会更有趣...
:: 部分伪元素
它允许您从web组件的Shadow DOM外部为其特定命名部分设置样式。
让我们把一些事情结合起来;想象一下下面的例子:
html
<my-element>
<h2 slot="header">Header Content</h2>
<p slot="content">Main Content</p>
</my-element>
这就是我们的web组件的样子(特别注意innerHTML的属性):
js
class MyElement extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({ mode: "open" });
shadow.innerHTML = `
<style>
div {
border: 3px solid blue;
}
</style>
<div part="header"><slot name="header"></slot></div>
<hr/>
<div part="content"><slot name="content"></slot></div>
`;
}
}
customElements.define("my-element", MyElement);
现在解释这一点的最好方法是用边界将其可视化。默认情况下,shadow DOM中的<div>元素有一个蓝色边框。我们想给封装头槽的<div>一个绿色边框,我们可以访问:
css
/* style our default h2 */
h2 {
margin-block: 30px;
color: red;
border: 3px solid red;
}
/* style our web component parts green border for header */
my-element::part(header) {
border: 3px solid green;
}
web组件的开发人员体验
我已经给你看了一些基本的例子,现在是时候说实话了......写这样的web组件不是一种很好的开发体验......至少在我看来是这样。它似乎适用于基本示例,但我只是喜欢编辑器中的一些结构和颜色,而不是将每个输出都放入字符串中。
受我的一位同事Lucien Immink的启发,他一直在巡回演出,并发表了一篇演讲,称一个名为"Lit"的库火了。我决定试一试...是的!写一个小的web组件会更有趣。谢谢Lucien的热提示。
Lit:使用库来帮助创建web组件
Lit库旨在使使用web组件更容易、更高效。它提供了几个优点,可以通过正常的方式来减轻一些负担。
Lit为定义组件提供了更具声明性的语法。使用这种方法可以使我们的代码更容易理解和管理,而不是直接处理Web组件API时需要更复杂的样式。它还有一个整洁的模板系统,它结合了HTML和JavaScript模板文字,使处理动态内容更加方便。这不仅有助于在我们的编辑器中使用一些漂亮的颜色,而且有助于它们的更新策略,即只更新DOM中已更改的部分。与手动更新相比,这可以提高性能。
综合所有这些因素,如果你对web组件很认真,我想说这是值得一看的,因为这个库只有大约6kb的大小。
还有很多事情要做,比如实验性的服务器端渲染,但我只是从这个开始,需要自己深入了解细节。
最后的想法和演示
我刚刚开始研究整个web组件,我真的很喜欢我所看到的。我加入的太晚了,这已经在我的名单上有一段时间了。我喜欢这个网络平台,因为我对开放式用户界面有很高的兴趣,所以我受到启发,更深入地研究这类东西。
我喜欢web组件背后的哲学,并相信这是一件重要的事情。随着公司的不断壮大,对不同框架的需求也在增加,这使得web组件成为集成到公司不断发展的技术堆栈中的完美选择。
最近很多人都在谈论它们,我只是试一试。起初,我发现基础知识和行话很难掌握,所以我希望写这篇文章能为其他有同样困难的人扫清一些迷雾。