Web Component入门

说明: 以下使用Web组件来表示Web Component

正文:

在web开发中,代码复用已成为一个聚焦重点。作为一名开发者,我们可能会遇到这样的场景,在多个地方使用一个代码片段来表示自定义的UI。如果我们不是很小心的写出,这可能会让整个代码结构变得不可管理。Web组件提供了一个原生的API来构建可复用的UI块。

什么是Web组件?

Web组件是一系列用来帮助我们创建可复用、具备封装的自定义HTML UI元素的浏览器底层的API。Web组件被认为更加好,是因为他们可以用任意的库或者框架创建,而且你可以立马使用原生JavaScript开始创建你自己的Web组件。

使用Web组件的一大优势在于他们已经在除了微软Edge外其他浏览器中可用,但是我们并不需要担心,因为已经有Polyfills可以解决这个问题。

Web组件由3个主要的技术组成,他们是主要支柱并作为API来构建Web组件。

  • 自定义元素(Custom Elements)
  • 模板(Templates)
  • 影子DOM(Shadow DOM)

让我们来进一步了解这些技术。

1. 自定义元素(Custom Elements)

这些是JavaScript API的集合,可以帮助你创建自己的HTML元素,并且控制你的DOM和行为。我们可以构建他们的层级和指示他们对行为变化做出的响应。例如,你可以创建一个元素像这样<my-element></my-element>

2. 模板(Templates)

模板是用户定义的模板在页面加载时并不渲染。之后可以通过创建一个组件实例来多次复用。

3. 影子DOM(Shadow DOM)

影子DOM是JavaScript API组合用以连接封装的DOM。这将会从主文档对象模型中独立渲染,并且他们的行为特性将会保持私有,因此代码片段就不会和代码结构中的其他部分冲突。使用影子DOM后CSS和JavaScript就会像<iframe>一样分离。

生命周期回调

生命周期回调是定义在自定义元素类定义中的函数。他们有自己唯一的定义目的。他们用于操作我们自定义元素的行为。

  • connectedCallback: 这个特殊的函数会在我们的自定义元素初始连接到DOM时进行调用。
  • adoptedCallback: 这个函数会在我们的自定义函数移动到一个新的文档时调用。
  • attributeChangedCallback: 如果在我们的自定义元素中有属性变化,例如属性的变更、增加或者删掉,这个特殊的函数会被调用。
  • disconnectedCallback: 这个特殊的函数当我们的自定义元素从DOM中断开时调用。

现在让我们来看看如何使用原生JavaScript来创建一个Web组件。通过做完这个教程,你可以了解Web组件。

实战

我们要构建什么?

我们要构建一个显示一张当前热门图片的Web组件。我们会使用Giphy API来获取gif,你的代码结构在实现完成后会是如下:

1
2
3
--index.html
--card.js
--services.js

构建教程

首先,我们要创建一个类来包含我们想创建的Web组件的行为。创建一个card.js的文件,并创建一个如下的类。

1
2
3
4
5
6
7
8
class CardComponent extends HTMLElement {
constructor (){
super();

//Your implementaion goes here

}
}

在类的构造函数中,你需要通过Element.attachShadow()方法将影子DOM的影子根(shadow root)添加到文档的当前HTML元素中。接着使用<template>标签在index.html文件中创建HTML模板。这个模板如下:

1
2
3
4
5
<template id="card-view">
<h1>Web Component</h1>
<p id="card-title">Example</p>
<img id="gif-view"/>
</template>

在添加模板到我们的index.html文件中后,我们可以使用DOM方法来克隆上面的模板并添加到我们的影子DOM。这需要在构造函数中完成。

1
2
3
4
5
6
7
8
9
10
11
class CardComponent extends HTMLElement {
constructor (){
super();
const shadow = this.attachShadow({mode: 'open'});

// Clone the template so that it can be attched to the shadowroot
const template = document.getElementById('card-view');
const templateInstance = template.content.cloneNode(true);
shadow.appendChild(templateInstance);
}
}

就像我之前提到的,我们应该再写一个函数来从Giphy API中获取gif。从API中我们将获取到当前热门的图片,以及这个图片上传者提供的标题。在我们开始写这个函数前,先创建一个单独的文件services.js用以放置URL和API key。创建文件并放置以下代码和你申请的API key。

1
2
3
const API_KEY = '*YOUR_API_KEY*';
const url = `http://api.giphy.com/v1/gifs/trending?api_key=` + API_KEY + `&limit=1`;
export {API_KEY, url}; // export the url so that i can be used extrnally.

创建services.js文件后,添加以下的代码到你的card.js文件顶部,这样你就可以使用URL来获取gif图片了。

1
import { url } from './services.js';

你可以从这个链接获取你自己的API key: https://developers.giphy.com/

跳回到card.js文件,并添加以下函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
render(shadowElem, data){
const shadowRoot = shadowElem.shadowRoot;
shadowRoot.getElementById('card-title').innerHTML = data.name;
shadowRoot.getElementById('gif-view').src = data.url;
}

async fetchFromGiphy (){
const res = await fetch(url);
const json = await res.json();
const gifUrl = json['data']['0'].images['fixed_height_small'].url;
const gifName = json['data']['0'].title;
const gifObject = {
name: gifName,
url: gifUrl
}
return gifObject;
}

让我来解释一下这些函数。

fetchFromGiphy(): 这个函数使用async/await获取热门的gif和这个gif的标题,并作为对象进行返回。

render(): 这个函数用于注入值到影子DOM的元素中。

接着,让这些函数在生命周期回调中被调用。实际上,我们需要当我们的自定义元素连接到DOM时调用这两个函数。我们有connectedCallback()函数来实现。

1
2
3
4
async connectedCallback() {
this.gifObj = await this.fetchFromGiphy();
this.render(this, this.gifObj);
}

最后,使用customElements.define()函数来定义我们的自定义元素。当定义一个自定义元素时,有一些基本原则需要记在心里。define()函数的第一个参数应该是代码自定义元素名称的字符串。他们不能是一个单独的单词,而是由-字符在中间。第二个参数我们的定义元素行为的类对象。

1
customElements.define(‘card-component’, CardComponent);

现在你已经定义了你的组件,添加card.js文件到你的index.html文件中。你可以在HTML文档的任意地方使用<card-component>元素。最后的index.html如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang="en">
<head>
<title>Web Component</title>
</head>
<body>

<template id="card-view">
<h1>Web Component</h1>
<p id="card-title">Example</p>
<img id="gif-view"/>
</template>

<card-component></card-component>
<script src="./card.js" type="module"></script>
</body>
</html>

为了运行,你需要一个服务器。从命令行中全局安装static-server:

1
npm install -g static-server

从你的Web组件项目目录下运行static-server命令:

1
static-server

好了,恭喜!你现在已经拥有你自己的组件。

结论

这篇文章总结了Web组件的基础。这是Web组件的理论和实现。Web组件在帮助代码复用上很有用。你可以从这个项目中检出所有代码。

您的支持将鼓励我继续创作!
0%