「这是我参与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>
标签被称为内容模板元素是一种用于保存客户端内容机制,该内容在加载页面时不会呈现( 默认的 display
为 none
),但随后可以在运行时使用JavaScript实例化。
在 Web Component 中的 template 作用是一样的,在它创建的 html ,在加载完后的页面是不会显示的,这样子的话,我们就可以创建一堆的 template 标签 用来保存视图,然后在需要的时候通过js脚本进行渲染,实现一个按需加载的效果
比如正常情况下
<!-- <template> -->
<img src="https://img1.baidu.com/it/u=940811906,4152926232&fm=26&fmt=auto" alt="加载失败">
<!-- </template> -->
复制代码
会在浏览器上显示一张图片:
而使用 <template>
标签做一个包裹则不会显示,因为 <template>
标签默认的 display
为 none
为什么要使用Template
在这之前就要大概说一下 Web Component 的实现,也就是如何将一个自定义元素变成 Web Components 组件
1.自定义一个HTML标签
<user-card></user-card>
复制代码
要注意的是自定义的元素必须包含连线,用来和原生的HTML标签区分开来
2.为这个自定义元素添加内容
首先定义一个类,注意这个类要继承HTMLElement,这样才能够拥有HTML元素的特性
class UserCard extends HTMLElement {
constructor() {
super();
}
}
复制代码
然后为这个类添加内容,再将这个类和自定义标签做一个绑定,这样类里面的内容才能反应到自定义标签上。绑定的过程用到了浏览器原生的 customElements.define() 方法。
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代码就不放上来了
这样我们就简单的实现了一个自定义的标签,接下来, <template>
的作用就在于:我们可以在它里面事先写好HTML结构,然后在这个类里面去使用它就可以了,这样子就可以省去很多在JavaScript中写dom的不方便
3.使用<template>
来完成上面的样式
我们可以直接在body中定义<template>
来存放我们想要等等添加到自定义标签里的内容,并且因为<template>
是不会被显示的,所以并不会影响页面视图。比如:
<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 来进行节点克隆,这样操作最后的结果和上面的是一样的
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样式,这样的样式可以定义不对外面产生影响,真正的实现组件化:
<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()
:
var shadow = this.attachShadow( { mode: 'closed'|'open' } );
复制代码
close
和 open
分别是对不对外开放这个组件
总结
使用Web Component能够很方便的封装一部分的代码轻松实现代码复用,减少html代码的编写亮。
引用外部文章:
<template>:内容模板元素 - HTML(超文本标记语言) | MDN
web component 【Template】 创建自己的简单SPA应用
Web Components 入门实例教程 - 阮一峰的网络日志