目录
- Web Components不兼容IE
- 困境
- Web Components核心技术
- 自定义元素
- HTML模板(template、slot)
- shadow root(影子Dom)
Web Components不兼容IE
2011年提出Web Components,为了解决代码复用问题,早于React、Vue;
相对于React、Vue组件,Web Components是原生组件,不限制接入方的技术,可以接入到React、Vue等技术框架中
困境
- 兼容性不足,需要主流浏览器的支持,需要平缓的过渡
- 没有标准的数据绑定机制、在处理自定义元素内部数据、UI更新、组件间参数传递时不够便捷和友好,目前来看大多还依赖于操控dom去实现UI更新
Web Components核心技术
- 自定义元素
- HTML模板
- 影子Dom
自定义元素
使用 window.customElements.define
自定义html标签元素,自定义元素需要我们用JS封装一个,我们在html内使用的自定义元素custom-button
就是该类的实例;
自定义标签的生命周期 constructor -> attributeChangedCallback -> connectedCallback
<!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>Document</title> </head> <body> <custom-button></custom-button> <script> class CustomButton extends HTMLElement { constructor() { super(); console.log("this", this); const info = document.createElement("span"); info.setAttribute("class", "test_custom"); info.textContent = "自测自定义标签"; var container = document.createElement("div"); container.classList.add("container"); this.append(info, container); } } customElements.define("custom-button", CustomButton); </script> </body> </html>
我们可以看到CustomButton
继承了HTMLElement
,也就是继承了HTML元素的特性,最后我们执行了this.append(DOM)
,也就是将元素内容添加到当前自定义标签
内,this
表示自定义元素实例
HTML模板(template、slot)
<template>
:包含一个html片段,不会在html初始化时渲染。主要作用是:通过JavaScript获取该代码片段将其放入自定义标签内显示,主要作用于自定义标签
<!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>Document</title> </head> <body> <template id="test_template"> <div class="container"> <span class="test_custom">自测自定义标签</span> </div> </template> <custom-button></custom-button> <script> class CustomButton extends HTMLElement { constructor() { super(); const dom = document.querySelector("#test_template").content; this.append(dom); } } customElements.define("custom-button", CustomButton); </script> </body> </html>
我们可以发现这种写法相对于前一种方式,更加易读
以及便捷
<slot>插槽
:给模板元素传值,增强模板元素的灵活性和通用性。 slot在使用过程中具备以下特性
- 必须在影子Dom种使用,否则不具备插槽的效果
- 给 Slots 传值的元素必须是自定义元素的直接子元素,否则传值失效
<!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>Document</title> </head> <body> <template id="test_template"> <div class="container"> <span class="test_custom">自测自定义标签</span> <slot name="userName" slot="userName"></slot> </div> </template> <custom-button> <div class="name_cls" slot="userName">张三</div> </custom-button> <script> class CustomButton extends HTMLElement { constructor() { super(); const dom = document.querySelector("#test_template").content; this.append(dom); } } customElements.define("custom-button", CustomButton); </script> </body> </html>
通过上图发现我们插入的<div class="name_cls">张三</div>
并没有插入到container节点内,主要是因为我们的slot没有用在影子dom种,所以浏览器将<div class="name_cls">张三</div>
当成其正常的元素进行渲染了;
<script> class CustomButton extends HTMLElement { constructor() { super(); const shadow = this.attachShadow({ mode: "closed" }); const dom = document.querySelector("#test_template").content; shadow.append(dom); } } customElements.define("custom-button", CustomButton); </script>
当我们将slot插入在影子dom,可以发现slot生效了;
另外需要注意的一个点,当使用slot的时候下边这个用法是错误的
// 错误示范 <custom-button> <div> //不能有这一层级 <div class="name_cls" slot="userName">张三</div> </div> </custom-button>
shadow root(影子Dom)
浏览器提供了一种机制用于隔离一段代码和另一段代码,说到这里你肯定想到iframe,但有时候iframe会显得非常的沉重以及隔离了太多,导致我们使用起来非常的麻烦; 我们可以利用shadow root将CSS和HTML绑定在一起封装成组件,并且其支持天然的样式隔离;
Element.attachShadow()
方法给指定的元素挂载一个 Shadow DOM,并且返回对 ShadowRoot 的引用。
<script> class CustomButton extends HTMLElement { constructor() { super(); const shadow = this.attachShadow({ mode: "closed" }); const dom = document.querySelector("#test_template").content; shadow.append(dom); } } customElements.define("custom-button", CustomButton); </script>
this.attachShadow({ mode: "closed" })
的closed
表示表示 Shadow DOM
是封闭的,不允许外部访问。如果mode
的值是open
,则表示内部的节点可以被外部访问;
添加样式
- 如果自定义元素需要样式,我们可以定义全局的样式,例如
custom-button{ ... }
- 正常情况我们应该将样式和自定义标签封装在一起
<!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>Document</title> </head> <body> <div>222</div> <template id="test_template"> <div class="container"> <span class="test_custom">自测自定义标签</span> <slot name="userName"></slot> </div> <style> :host { position: relative; top: 10px; } .test_custom { color: red; } div { border: 1px solid black; } </style> </template> <custom-button> <span slot="userName">张三</span> </custom-button> <script> class CustomButton extends HTMLElement { constructor() { super(); const shadow = this.attachShadow({ mode: "closed" }); const dom = document.querySelector("#test_template").content; shadow.append(dom); } } customElements.define("custom-button", CustomButton); </script> </body> </html>
:host
:表示当前的自定义元素节点;
另外可以发现我们定义的div样式只作用于了影子dom
内部元素,对于外部的div没有任何影响,证明了影子Dom的样式隔离特性
;
以上就是Web Components入门教程详解的详细内容,更多关于Web Components入门教程的资料请关注自由互联其它相关文章!