参考链接: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吧
我们的目标是做一个像这个一样的小组件!!!冲鸭!
定义一个类
构造函数必须是一个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
, 继承自自
元素。
template标签
Web Components API 提供了标签,可以在它里面使用 HTML 定义 DOM。
这个时候,我们要重新修改一下我们的HelloWorld类,使我们的这个类加载这个template。
class HelloWorld extends HTMLElement {
constructor() {
// 必须首先调用 super 方法
super();
var templateElem = document.getElementById('helloWorldTemplate')
var content = templateElem.content.cloneNode(true)
this.appendChild(content);
}
}
添加样式
给自定义元素添加元素,将样式写在里面,让样式只对自定义元素生效,不影响外部。
例子中的样式代码如下:
抽离参数
我们的自定义元素可能多次出现,所以像上面将他写死就与我们当初组件化的初衷相背离了,我们应该将参数抽离出来,像下面这样:
相对应的,应该在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的内容也相对应的修改为:
在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)
}
}
https://github.com/LemonTency/jichengHomework/blob/master/0211%E7%AC%AC%E4%B8%89%E5%91%A8%E5%89%8D%E7%AB%AF%E9%9B%86%E6%88%90/demo.html
组件化
在我们的实际开发过程中,可以将对应的JS代码和放在同一个文件中,成为独立的组件文件。网页只要加载这个脚本,就能使用对应的组件。
具体示例可以参照:
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