Web Component 中的 Template

语言: CN / TW / HK

highlight: a11y-dark theme: smartblue


「这是我参与11月更文挑战的第8天,活动详情查看:2021最后一次更文挑战」。

前言

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

在我们平时的开发当中,都知道要尽可以的重用代码。Web Components 就是用来创建封装功能的定制元素,然后可以在指定的地方重复使用。

它由三项主要技术组成:

1. Custom elements(自定义元素)
2. Shadow DOM(影子DOM)
3. HTML templates(HTML模板)

本篇主要来讲一下 HTML templates(HTML模板) 比如我们平常经常使用的vue框架的原理,也是基于这个实现的。

什么是Template

<template> 标签被称为内容模板元素是一种用于保存客户端内容机制,该内容在加载页面时不会呈现( 默认的 displaynone ),但随后可以在运行时使用JavaScript实例化。

在 Web Component 中的 template 作用是一样的,在它创建的 html ,在加载完后的页面是不会显示的,这样子的话,我们就可以创建一堆的 template 标签 用来保存视图,然后在需要的时候通过js脚本进行渲染,实现一个按需加载的效果

比如正常情况下

```html

<img src="https://img1.baidu.com/it/u=940811906,4152926232&fm=26&fmt=auto" alt="加载失败">

``` 会在浏览器上显示一张图片:

image.png

而使用 <template> 标签做一个包裹则不会显示,因为 <template> 标签默认的 displaynone

image.png

为什么要使用Template

在这之前就要大概说一下 Web Component 的实现,也就是如何将一个自定义元素变成 Web Components 组件

1.自定义一个HTML标签

html <user-card></user-card>

要注意的是自定义的元素必须包含连线,用来和原生的HTML标签区分开来

2.为这个自定义元素添加内容

首先定义一个类,注意这个类要继承HTMLElement,这样才能够拥有HTML元素的特性

js class UserCard extends HTMLElement { constructor() { super(); } }

然后为这个类添加内容,再将这个类和自定义标签做一个绑定,这样类里面的内容才能反应到自定义标签上。绑定的过程用到了浏览器原生的 customElements.define() 方法。

```js class UserCard extends HTMLElement { constructor() { super();

    let box = document.createElement('div');
    box.classList.add('box');

    let image = document.createElement('img');
    image.src = 'https://img1.baidu.com/it/u=940811906,4152926232&fm=26&fmt=auto';
    image.classList.add('image');

    let name = document.createElement('p');
    name.classList.add('name');
    name.innerText = 'zhangsan';

    let age = document.createElement('p');
    age.classList.add('email');
    age.innerText = '18';

    let button = document.createElement('button');
    button.classList.add('button');
    button.innerText = 'Follow';

    this.append(box);
    box.append(image, name, age, button);
}

} window.customElements.define('user-card', UserCard);//将类和自定义标签做绑定 ```

类当中最后的 this 代表的是这个自定义元素。这样之后,页面中的dom结构就已经生成了,可以在添上一些css样式,这里css代码就不放上来了

image.png

这样我们就简单的实现了一个自定义的标签,接下来, <template> 的作用就在于:我们可以在它里面事先写好HTML结构,然后在这个类里面去使用它就可以了,这样子就可以省去很多在JavaScript中写dom的不方便

3.使用<template> 来完成上面的样式

我们可以直接在body中定义<template>来存放我们想要等等添加到自定义标签里的内容,并且因为<template>是不会被显示的,所以并不会影响页面视图。比如:

html <template id="userCardTemplate"> <div class="box"> <img src="https://img1.baidu.com/it/u=940811906,4152926232&fm=26&fmt=auto" class="image"> <p class="name">zhangsan</p> <p class="age">18</p> <button class="button">Follow</button> </div> </template> 然后再将它添加到自定义标签当中,这里要注意,因为这个<template>中存储的样式不一定只使用一次,所以在添加的时候,要克隆一份标签添加进去,这里要使用 Node.cloneNode 来进行节点克隆,这样操作最后的结果和上面的是一样的

```js class UserCard extends HTMLElement { constructor() { super();

    var templateElem = document.getElementById('userCardTemplate');
    var content = templateElem.content.cloneNode(true);
    this.appendChild(content);
}

} ```

到这就能够看的出来,使用了<template>能够减少大量的在JS里进行节点的繁琐操作,万一这个组件非常的巨大,那么用JS去描述是非常的麻烦的

4.在 <template> 中封装样式

<template>不止是可以将大量的HTML写在其中,还可以在里面写css样式,这样的样式可以定义不对外面产生影响,真正的实现组件化:

html <template id="userCardTemplate"> <style> .box { width: 220px; background-color: rgb(180, 180, 180); margin: 20px auto; padding: 10px 0; border-radius: 8px; } img { display: block; width: 200px; height: 200px; margin: auto; } p { margin: 0; text-align: center; margin-top: 10px; font-weight: bold; } button { display: block; margin: 10px auto; text-align: center; width: 100px; height: 30px; border: none; border-radius: 4px; background-color: rgb(81, 199, 253); color: #fff; font-weight: bold; } </style> <div class="box"> <img src="https://img1.baidu.com/it/u=940811906,4152926232&fm=26&fmt=auto" class="image"> <p class="name">zhangsan</p> <p class="age">18</p> <button class="button">Follow</button> </div> </template>

内部有一个 :host 伪类可以代表元素本身

然后在类里面可以去设定 Shadow DOM 设定这部分里的代码于外部隔离,这里简单说明,只需要在类中设定this.attachShadow() :

js var shadow = this.attachShadow( { mode: 'closed'|'open' } );

closeopen 分别是对不对外开放这个组件

总结

使用Web Component能够很方便的封装一部分的代码轻松实现代码复用,减少html代码的编写亮。

引用外部文章:
<template>:内容模板元素 - HTML(超文本标记语言) | MDN
web component 【Template】 创建自己的简单SPA应用
Web Components 入门实例教程 - 阮一峰的网络日志