共计 4316 个字符,预计需要花费 11 分钟才能阅读完成。
本文翻译自:https://css-tricks.com/an-int…
本文首发于公众号:符合预期的 CoyPan
前端开发正在以惊人的速度发展。曾经的前端开发,技术栈都是很简单的,如今却越来越复杂。这一点从无数的文章、教程和 Twitter 上就可以看出来。在本文中,我将讨论为什么 Web Component 是一个很好的工具,可以在不使用复杂框架或构建步骤的情况下提供高质量的用户体验,而且不存在过时的风险。在这个由五部分组成的系列的后续文章中,我们将深入研究每个规范。
本系列假设您基本了解 HTML、CSS 和 JavaScript。如果您在其中一个领域感到软弱,不用担心,构建自定义元素实际上简化了许多前端开发中的复杂性。
系列文章:
An Introduction to Web Components (本文)
Crafting Reusable HTML Templates
Creating a Custom Element from Scratch
Encapsulating Style and Structure with Shadow DOM
Advanced Tooling for Web Components
到底什么是 Web Components
Web Components 由三种技术组成。这三种技术会一起使用。
Custome Elements。自定义元素十分简单,他们都是合法的 HTML 元素,拥有自定义的模板,表现以及标签名(例如:<one-dialog>)。可以通过一系列的 JavaScript API 来创建自定义元素。自定义元素是在标准 HTML 规范中定义的。
Shadow DOM。像一个 Iframe 一样,可以隔离 CSS 和 JavaScript。这是在标准 DOM 规范中定义的。
HTML templates。用户在 HTML 中定义的模板,只有调用的时候才会被渲染。<template> 标签是在标准 HTML 规范中定义的。
上述三种技术组成了 Web Components 规范。
HTML Modules 有可能会成为第四种技术。但是四大浏览器都还没有实现 HTML Modules。Chrome 团队已经声明将在未来的版本中实现 HTML Modules
Web Components 在目前所有的主流浏览中都是可以使用的,除了微软的 Edge 和 IE11,但是也有 polyfill 可以使用。
将上述的三种技术称为 Web Components 在技术上来说是准确的,Web Components 这个术语本身也有一些超载。因此,每种技术都可以独立使用或与其他技术结合使用。换句话说,它们并不相互排斥。
让我们快速看一下上述三种技术。我们将在其他文章中,深入了解他们。
Custome elements
就像名字所显示的那样,custome elements 就是 HTML 元素,比如 <div>、<section>、<article>,但是我们通过浏览器的 API 自己给元素命名。自定义元素与标准 HTML 元素(尖括号中的名称)一样,只是它们中总是有一个破折号,如 <news-slider> 或 <bacon-cheesburger>。更进一步,浏览器厂商们都已经承诺不会再新增带有破折号的内置元素,避免和自定义元素产生冲突。
自定义元素包含自己的语义、行为、标记,并且可以跨框架和浏览器共享。
示例可以参考这里:
https://codepen.io/calebdwill…
在这个例子中,我们定义了我们自己的 HTML 元素 <my-component>。不可否认的是,这个元素做的事情并不多,但是这就是最基本的自定义元素构建方法。所有的自定义元素都必须以某种方式上继承 HTMLElement,这样才能在浏览器上注册上该元素。
自定义元素不依赖与第三方框架。浏览器厂商们正致力于规范的向后兼容性,不过都保证只要按照规范编写的组件都不会受到 API 大改的影响。更重要的是,这些自定义元素在当今的主流框架 (Angular、React、Vue) 中,只需要稍做修改,就可以做到开箱即用。
Shadow DOM
Shadow DOM 是对 DOM 的一个封装。这使得作者能够有效地将 DOM 片段彼此隔离开来,包括任何可以用作 CSS 选择器的东西以及与之关联的样式。通常情况下,document 范围内的内容都被称为 light DOM,shadow root 中的内容被称为 shadow DOM。
当我们使用 light DOM 的时候,我们可以通过 document.querySelector(‘selector’)来选中某个 DOM,或者通过 element.querySelector(‘selector’)来获取每个元素的子元素。同样的,shadow root 的子元素可以通过 shadowRoot.querySelector 来获取,这里的 shadowRoot 是一个 document fragment。不同的地方是,shadow root 的子元素无法在 light dom 中被选中。例如,如果我们的 shadow root 中有一个 <button>,使用 shadowRoot.querySelector(‘button’)可以得到我们的 button,但是调用 document 的 querySelector 就取不到这个 button,因为这个 button 属于不同的 DocumentOrShadowRoot 实例。样式选择器也是一样的。
从某种意义上来说,shadow dom 有点像一个 iframe,其中的内容与 document 的其他部分隔开了。不过,当我们创建一个 shadow root 的时候,我们仍然可以完全控制页面中这部分的内容,只是说需要在一定的作用域下。这就是我们所说的封装。
如果你曾经写过一个重用相同的 id 或者依赖 CSS-in-JS 工具,CSS 命名策略 (比如 BEM) 的组件,shadow dom 或许提升你的开发体验。
想象一下如下的场景:
<div>
<div id=”example”>
<!– Pseudo-code used to designate a shadow root –>
<#shadow-root>
<style>
button {
background: tomato;
color: white;
}
</style>
<button id=”button”>This will use the CSS background tomato</button>
</#shadow-root>
</div>
<button id=”button”>Not tomato</button>
</div>
除了 <#shadow-root> 的伪代码(没有 HTML 元素,用来分割 shadow 的边界),HTML 是完全合法的。为了实现上面的 HTML,我们需要运行下面的代码:
const shadowRoot = document.getElementById(‘example’).attachShadow({mode: ‘open’});
shadowRoot.innerHTML = `<style>
button {
color: tomato;
}
</style>
<button id=”button”>This will use the CSS color tomato <slot></slot></button>`;
shadow root 也可以使用 <slot> 元素来从其内部的文档内容中包含内容。使用 slot 可以把外部文档中的用户内容放到 shadow root 目录中的指定位置。
示例可以参考这里:
https://codepen.io/calebdwill…
HTML templates
适当命名的 HTML<template> 元素允许我们在正常 HTML 流中消除代码的可重用模板。这些模板不会立即被渲染,但可以在以后使用。
<template id=”book-template”>
<li><span class=”title”></span> — <span class=”author”></span></li>
</template>
<ul id=”books”></ul>
上面的例子不会渲染任何的东西,直到我们使用 script 操作了这个模板,实例化代码并告诉浏览器如何操作它。
const fragment = document.getElementById(‘book-template’);
const books = [
{title: ‘The Great Gatsby’, author: ‘F. Scott Fitzgerald’},
{title: ‘A Farewell to Arms’, author: ‘Ernest Hemingway’},
{title: ‘Catch 22’, author: ‘Joseph Heller’}
];
books.forEach(book => {
// Create an instance of the template content
const instance = document.importNode(fragment.content, true);
// Add relevant content to the template
instance.querySelector(‘.title’).innerHTML = book.title;
instance.querySelector(‘.author’).innerHTML = book.author;
// Append the instance ot the DOM
document.getElementById(‘books’).appendChild(instance);
});
请注意,此示例创建了一个模板(<template id=“book template”>),而不使用任何其他 Web Components 技术,再次说明 Web Components 中的三种技术可以独立使用或共同使用。
表面上,可以使用模板 API 书写一个任意结构的模板,并且在后续的代码中创建这个模板。站点上的另外一个页面可能会使用相同的服务,但是使用另外的结构来创建模板:
<template id=”book-template”>
<li><span class=”author”></span>’s classic novel <span class=”title”></span></li>
</template>
<ul id=”books”></ul>
可以点击这里查看示例:
https://codepen.io/calebdwill…
总结
随着 Web 开发越来越复杂,像我们这样的开发者开始将越来越多的开发推迟到 Web 平台本身,而 Web 平台本身也在不断成熟。Web Components 规范是一组低级 API,随着开发者的发展,这些 API 将随着我们的需求不断增长和发展。