Web Components

Web Components 是一套不同的技术,允许您创建可重用的定制元素(它们的功能封装在您的代码之外)并且在您的web应用中使用它们。

作为开发者,我们都知道尽可能多的重用代码是一个好主意。这对于自定义标记结构来说通常不是那么容易 — 想想复杂的HTML(以及相关的样式和脚本),有时您不得不写代码来呈现自定义UI控件,并且如果您不小心的话,多次使用它们会使您的页面变得一团糟。

Web Components旨在解决这些问题 — 它由三项主要技术组成,它们可以一起使用来创建封装功能的定制元素,可以在你喜欢的任何地方重用,不必担心代码冲突。

基本概念

  • Custom elements(自定义元素):一组JavaScript API,允许您定义custom elements及其行为,然后可以在您的用户界面中按照需要使用它们。
  • Shadow DOM(影子DOM):一组JavaScript API,用于将封装的“影子”DOM树附加到元素(与主文档DOM分开呈现)并控制其关联的功能。通过这种方式,您可以保持元素的功能私有,这样它们就可以被脚本化和样式化,而不用担心与文档的其他部分发生冲突。
  • HTML templates(HTML模板): <template> 和 <slot> 元素使您可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用。
  • HTML导入 (HTML Imports)

实现web component的基本方法通常如下所示:

  1. 创建一个类或函数来指定web组件的功能,如果使用类,请使用 ES6的类语法。
  2. 使用 CustomElementRegistry.define() 方法注册您的新自定义元素 ,并向其传递要定义的元素名称、指定元素功能的类、以及可选的其所继承自的元素。
  3. 如果需要的话,使用Element.attachShadow() 方法将一个shadow DOM附加到自定义元素上。使用通常的DOM方法向shadow DOM中添加子元素、事件监听器等等。
  4. 如果需要的话,使用 <template> 和<slot> 定义一个HTML模板。再次使用常规DOM方法克隆模板并将其附加到您的shadow DOM中。
  5. 在页面任何您喜欢的位置使用自定义元素,就像使用常规HTML元素那样。

实例教程

上面介绍了Web Components的一些基本概念,接下来配合这些基本概念,我们将配备一些实例。

下图是一个用户卡片。

Web Components基本概念及实例教程

 本文演示如何把这个卡片,写成 Web Components 组件。网页只要插入下面的代码,就会显示用户卡片。

1 <user-card></user-card>

注意:这种自定义的 HTML 标签,称为自定义元素(custom element)。根据规范,自定义元素的名称必须包含连词线,用与区别原生的 HTML 元素。所以,<user-card>不能写成<usercard>。

customElements.define()

自定义元素需要使用 JavaScript 定义一个类,所有<user-card>都会是这个类的实例。

1 class UserCard extends HTMLElement {
2     constructor() {
3         super();
4     }
5 }

上面代码中,UserCard就是自定义元素的类。注意,这个类的父类是HTMLElement,因此继承了 HTML 元素的特性。

接着,使用浏览器原生的customElements.define()方法,告诉浏览器<user-card>元素与这个类关联。

1 window.customElements.define('user-card', UserCard);

自定义元素的内容

自定义元素<user-card>目前还是空的,下面在类里面给出这个元素的内容。

Web Components基本概念及实例教程

上面代码最后一行,this.append()的this表示自定义元素实例。

完成这一步以后,自定义元素内部的 DOM 结构就已经生成了。

template标签

使用 JavaScript 写上一节的 DOM 结构很麻烦,Web Components API 提供了<template>标签,类似vue书写组件的方式,可以在它里面使用 HTML 定义 DOM。

Web Components基本概念及实例教程

然后,改写一下自定义元素的类,为自定义元素加载<template>

Web Components基本概念及实例教程

上面代码中,获取<template>节点以后,克隆了它的所有子元素,这是因为可能有多个自定义元素的实例,这个模板还要留给其他实例使用,所以不能直接移动它的子元素。

到这一步为止,完整的代码如下

Web Components基本概念及实例教程

添加样式

自定义元素还没有样式,可以给它指定全局样式,比如下面这样。

1 user-card {
2     /* ... */
3 }

但是,组件的样式应该与代码封装在一起,只对自定义元素生效,不影响外部的全局样式。所以,可以把样式写在<template>里面,类似scss里面使用scoped的标签。

Web Components基本概念及实例教程

注意:上面代码中,<template>样式里面的:host伪类,指代自定义元素本身。

自定义元素的参数

<user-card>内容现在是在<template>里面设定的,为了组件复用,我们希望把它改成传递参数的形式:

Web Components基本概念及实例教程

那么<template>代码也相应改造

Web Components基本概念及实例教程

最后,改一下类的代码,把参数加到自定义元素里面

Web Components基本概念及实例教程

Shadow DOM

我们不希望用户能够看到<user-card>的内部代码,Web Component 允许内部代码隐藏起来,这叫做 Shadow DOM,即这部分 DOM 默认与外部 DOM 隔离,内部任何代码都无法影响外部。

自定义元素的this.attachShadow()方法开启 Shadow DOM,详见下面的代码。

Web Components基本概念及实例教程

上面代码中,this.attachShadow()方法的参数{ mode: 'closed' },表示 Shadow DOM 是封闭的,不允许外部访问。

至此,这个 Web Component 组件就完成了,完整代码可以访问这里。可以看到,整个过程还是很简单的,不像第三方框架那样有复杂的 API。

组件的扩展

在前面的基础上,可以对组件进行扩展。

(1)与用户互动

用户卡片是一个静态组件,如果要与用户互动,也很简单,就是在类里面监听各种事件。

1 this.$button = shadow.querySelector('button');
2 this.$button.addEventListener('click', () => {
3  // do something
4 });

(2)组件的封装

上面的例子中,<template>与网页代码放在一起,其实可以用脚本把<template>注入网页。这样的话,JavaScript 脚本跟<template>就能封装成一个 JS 文件,成为独立的组件文件。网页只要加载这个脚本,就能使用<user-card>组件。

致谢

原文地址:https://www.cnblogs.com/guchengnan/p/14498718.html