浏览器原理 27 # WebComponent
Posted 凯小默
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浏览器原理 27 # WebComponent相关的知识,希望对你有一定的参考价值。
说明
浏览器工作原理与实践专栏学习笔记
什么是组件化?
特点:对内高内聚,对外低耦合。
对内各个元素彼此紧密结合、相互依赖,对外和其他组件的联系最少且接口简单。
阻碍前端组件化的因素
比如:在页面中嵌入第三方内容时,需要确保第三方的内容样式不会影响到当前内容,同样也要确保当前的 DOM 不会影响到第三方的内容。
CSS 是如何阻碍前端组件化的
例子:比如不同人分别写了不同的全局样式,个人测试没问题,但是合并时会出现 CSS 属性影响到其他外部的标签的样式
<style>
p {
background-color: brown;
color: cornsilk
}
</style>
<p>time.geekbang.org</p>
<style>
p {
background-color: red;
color: blue
}
</style>
<p>time.geekbang</p>
显然,CSS 的全局属性会阻碍组件化。
DOM 也是阻碍组件化的一个因素,因为在页面中任何地方都可以直接读取和修改 DOM。
WebComponent 组件化开发
上面我们了解到了:CSS 和 DOM 是阻碍组件化的两个因素,WebComponent 给出的解决思路
WebComponent 提供了对局部视图封装能力,可以让 DOM、CSSOM 和 javascript 运行在局部环境中,这样就使得局部的 CSS 和 DOM 不会影响到全局。
WebComponent 是怎么实现组件化的
Web Components 概念
Web Components旨在解决这些问题 — 它由三项主要技术组成,它们可以一起使用来创建封装功能的定制元素,可以在你喜欢的任何地方重用,不必担心代码冲突。
- Custom elements(自定义元素):一组JavaScript API,允许您定义custom elements及其行为,然后可以在您的用户界面中按照需要使用它们。
- Shadow DOM(影子DOM):一组JavaScript API,用于将封装的“影子”DOM树附加到元素(与主文档DOM分开呈现)并控制其关联的功能。通过这种方式,您可以保持元素的功能私有,这样它们就可以被脚本化和样式化,而不用担心与文档的其他部分发生冲突。
- HTML templates(HTML模板):
<template>
和<slot>
元素使您可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用。
Web Components 使用
实现 web component 的基本方法通常如下所示:
- 创建一个类或函数来指定web组件的功能,如果使用类,请使用 ECMAScript 2015 的类语法。
- 使用
CustomElementRegistry.define()
方法注册您的新自定义元素 ,并向其传递要定义的元素名称、指定元素功能的类、以及可选的其所继承自的元素。 - 如果需要的话,使用
Element.attachShadow()
方法将一个 shadow DOM 附加到自定义元素上。使用通常的 DOM 方法向 shadow DOM 中添加子元素、事件监听器等等。 - 如果需要的话,使用
<template>
和<slot>
定义一个html模板。再次使用常规DOM方法克隆模板并将其附加到您的shadow DOM中。 - 在页面任何您喜欢的位置使用自定义元素,就像使用常规HTML元素那样。
Web Components 例子
要使用 WebComponent 需要实现下面三步:
1.使用 template 属性来创建模板。
利用 DOM 可以查找到模板的内容,但是模板元素是不会被渲染到页面上的,在模板的内部定义样式信息。
<!-- 定义模板样式 -->
<template id="kxm-template">
<style>
p {
background-color: green;
color: white;
}
div {
width: 200px;
background-color: blue;
border: 3px solid red;
border-radius: 10px;
}
</style>
<div>
<p>kxm</p>
<p>kaimo313</p>
</div>
<script>
function foo() {
console.log('template log');
}
</script>
</template>
2.创建一个类
- 查找模板内容;
- 创建影子 DOM;
- 再将模板添加到影子 DOM 上。
可以把影子 DOM 看成是一个作用域,其内部的样式和元素是不会影响到全局的样式和元素的,而在全局环境下,要访问影子 DOM 内部的样式或者元素也是需要通过约定好的接口的。
<!-- 创建一个类 -->
<script>
class Kaimo313 extends HTMLElement {
constructor() {
super()
// 获取组件模板
const content = document.querySelector('#kxm-template').content;
// 创建影子DOM节点
const shadowDOM = this.attachShadow({ mode: 'open' });
// 将模板添加到影子DOM上
shadowDOM.appendChild(content.cloneNode(true));
}
}
// 使用 customElements.define 来自定义元素
customElements.define('kaimo-313', Kaimo313);
</script>
3.使用该元素
<!-- 使用该元素 -->
<kaimo-313></kaimo-313>
<div>
<p>kxm</p>
<p>kaimo313</p>
</div>
<kaimo-313></kaimo-313>
完整的代码展示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>12.Web Components 例子</title>
</head>
<body>
<h1>kxm 测试 Web Components 例子</h1>
<!-- 定义模板样式 -->
<template id="kxm-template">
<style>
p {
background-color: green;
color: white;
}
div {
width: 200px;
background-color: blue;
border: 3px solid red;
border-radius: 10px;
}
</style>
<div>
<p>kxm</p>
<p>kaimo313</p>
</div>
<script>
function foo() {
console.log('template log');
}
</script>
</template>
<!-- 创建一个类 -->
<script>
class Kaimo313 extends HTMLElement {
constructor() {
super()
// 获取组件模板
const content = document.querySelector('#kxm-template').content;
// 创建影子DOM节点
const shadowDOM = this.attachShadow({ mode: 'open' });
// 将模板添加到影子DOM上
shadowDOM.appendChild(content.cloneNode(true));
}
}
// 使用 customElements.define 来自定义元素
customElements.define('kaimo-313', Kaimo313);
</script>
<!-- 使用该元素 -->
<kaimo-313></kaimo-313>
<div>
<p>kxm</p>
<p>kaimo313</p>
</div>
<kaimo-313></kaimo-313>
</body>
</html>
使用影子 DOM 的输出效果
浏览器如何实现影子 DOM
影子 DOM 的作用
- 影子 DOM 中的元素对于整个网页是不可见的;
- 影子 DOM 的 CSS 不会影响到整个网页的 CSSOM,影子 DOM 内部的 CSS 只对内部的元素起作用。
影子 DOM 示意图
影子 DOM 都有一个 shadow root 的根节点
浏览器怎么实现 DOM API 无法直接查询到影子 DOM 的内部元素?
当通过 DOM 接口去查找元素时,渲染引擎会去判断 kaimo-313 属性下面的 shadow-root 元素是否是影子 DOM,如果是,那么就直接跳过 shadow-root 元素的查询操作。
浏览器怎么实现渲染出来的效果就是影子 DOM 内部定义的样式?
当生成布局树的时候,渲染引擎也会判断 kaimo-313 属性下面的 shadow-root 元素是否是影子 DOM,如果是,那么在影子 DOM 内部元素的节点选择 CSS 样式的时候,会直接使用影子 DOM 内部的 CSS 属性。
以上是关于浏览器原理 27 # WebComponent的主要内容,如果未能解决你的问题,请参考以下文章
聚合物2.0 webcomponent带有切片的饼图选项抛出错误 - 无法定义toLowerCase未定义
Angular 9 Elements:如何创建一个独立的 WebComponent(包含所有依赖项)?
当 dom 中不再存在元素时,SetInterval 继续在 webcomponent 中运行