参考链接:https://www.robinwieruch.de/web-components-tutorial
http://www.ruanyifeng.com/blog/2019/08/web_components.html
https://mp.weixin.qq.com/s/KsPpmBrLsu0HjYWuzyAdgQ
https://segmentfault.com/a/1190000019115050
前置知识:
- appendChild() 方法可向节点的子节点列表的末尾添加新的子节点。
xxx.appendChild(node)
node指的是你要添加的节点对象。
为什么要使用web components
现在很多人都使用框架进行开发,例如Vue,Angluar,React,组件化开发已经成为大家的日常,但是,有没有想过,如果不需要框架就能实现可复用的前端组件,或者说在不同的框架之间使用同一套组件,那是不是会掀起一阵新的浪潮?
web components就是这样的一套功能组件,只需要HTML,CSS和JavaScript就能创建能运行在任何浏览器上的可复用组件了。
开始动手搭建我们的web components吧
我们的目标是做一个像这个一样的小组件!!!冲鸭!
![](https://img.haomeiwen.com/i7728915/9a681647bbd8be9e.png)
定义一个类
构造函数必须是一个ES6的类,
class HelloWorld extends HTMLElement {
constructor() {
// 必须首先调用 super 方法
super();
// 元素的功能代码写在这里
...
}
}
注册一个 custom emelent
使用customElements.define
来注册一个 custom emelent,这个方法接受三个参数:
- 所创建的元素名称的符合,不能为单个单词,中间必须要用短横线连接,方便与原生的HTML元素区别开来。
- 用于定义元素行为的类
- 可选参数,一个包含
extends
属性的配置对象,是可选参数。它指定了所创建的元素继承自哪个内置元素,可以继承任何内置元素。
看下实例:
customElements.define('hello-world', HelloWorld, { extends: 'p' });
这个元素叫做 hello-world
,它的类对象是 HelloWorld
, 继承自自<p>元素。
template标签
Web Components API 提供了<template>标签,可以在它里面使用 HTML 定义 DOM。
<template id="helloWorldTemplate">
<div class="container">
<p class="title">2019前端面试技巧</p>
<p class="text">掌握最新面试技巧,面试题,让你在前端面试中脱颖而出。</p>
<a class="detail">查看详情</p>
</div>
</template>
这个时候,我们要重新修改一下我们的HelloWorld类,使我们的这个类加载这个template。
class HelloWorld extends HTMLElement {
constructor() {
// 必须首先调用 super 方法
super();
var templateElem = document.getElementById('helloWorldTemplate')
var content = templateElem.content.cloneNode(true)
this.appendChild(content);
}
}
添加样式
给自定义元素添加元素,将样式写在<template>里面,让样式只对自定义元素生效,不影响外部。
例子中的样式代码如下:
<style>
.container {
background-image: url(http://img.mukewang.com/595228110001155208000480.jpg);
background-size: 100%;
float: left;
width: 475px;
height: 124px;
border-radius: 6px;
color: #fff;
margin: 0 10px 36px 20px;
box-sizing: border-box;
padding: 24px 32px 0;
}
.detail {
margin-top: 8px;
font-size: 12px;
font-weight: 200;
color: rgba(240, 20, 20, 0.6);
line-height: 16px;
}
.title {
font-size: 20px;
line-height: 24px;
margin: 2px;
color: rgba(255, 255, 255, 0.8);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.text {
font-size: 12px;
line-height: 24px;
color: rgba(255, 255, 255, 0.6);
font-weight: 200;
margin-top: 5px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
抽离参数
我们的自定义元素可能多次出现,所以像上面将他写死就与我们当初组件化的初衷相背离了,我们应该将参数抽离出来,像下面这样:
<hello-world
title="2019前端面试技巧"
text="掌握最新面试技巧,面试题,让你在前端面试中脱颖而出。"
img="url(http://img.mukewang.com/595228110001155208000480.jpg)"
></hello-world>
相对应的,应该在HelloWorld类中对参数进行处理
class HelloWorld extends HTMLElement {
constructor() {
// 必须首先调用 super 方法
super();
var templateElem = document.getElementById('helloWorldTemplate')
var content = templateElem.content.cloneNode(true)
content.querySelector(
'.container'
).style.backgroundImage = this.getAttribute('img')
content.querySelector(
'.container>.title'
).innerText = this.getAttribute('title')
content.querySelector(
'.container>.text'
).innerText = this.getAttribute('text')
this.appendChild(content);
}
}
此时,template的内容也相对应的修改为:
<template id="helloWorldTemplate">
<style>...</style>
<div class="container">
<p class="title"></p>
<p class="text"></p>
<a class="detail">查看详情</p>
</div>
</template>
在style中,将样式删掉background-image这个属性
即将大功告成,再来研究研究shadow DOM,将这一部分的DOM和外面的DOM隔绝起来吧!
Shadow DOM
使用attachShadow()方法开启 Shadow DOM,attachShadow的参数为mode。
mode: 一个指定Shadow DOM封装模式的字符串,可以是下列项目之一:
open 指定为开放的封装模式,则我们可以通过挂载时使用的真实元素获取到shadow-DOM。
closed 指定为关闭的封装模式,不允许外部访问。
class HelloWorld extends HTMLElement {
constructor() {
super()
var shadow = this.attachShadow({ mode: 'open' })
var templateElem = document.getElementById('helloWorldTemplate')
var content = templateElem.content.cloneNode(true)
shadow.appendChild(content)
}
}
组件化
在我们的实际开发过程中,可以将对应的JS代码和<template>放在同一个文件中,成为独立的组件文件。网页只要加载这个脚本,就能使用对应的组件。
具体示例可以参照:
https://github.com/LemonTency/jichengHomework/tree/master/0211%E7%AC%AC%E4%B8%89%E5%91%A8%E5%89%8D%E7%AB%AF%E9%9B%86%E6%88%90/web-components-starter-kit-master
网友评论