赞
踩
web component
是web原生提供的封装组件的方式,让开发者定义一些可重复使用的自定义元素。主要包含custom elements
、shadow dom
、html templates
部分,分别用于注册自定义元素、提供shadow-dom
接口,为自定义元素的样式和脚本提供一个隔离的环境、通过template
和slot
编写自定义元素的结构模板。
一个web component
就是一个我们可以在正常dom中使用的自定义元素。自定义元素只需要包含标记结构、样式以及脚本三个部分,最后再对新的自定义元素进行一个注册。
首先是注册,通过CustomElementRegistry.define()
方法完成,CustomElementRegistry
包含自定义元素的相关功能,可以通过Window.customElements
访问它的引用。例如:
customElements.define('element-a', ElementA, { extends: 'p' })
可以看到define
函数包含三个参数:
1.自定义元素名
2.包含自定义元素内容的类
3.可选参数,包含extends
属性的对象,指定了创建的元素继承自哪个内置元素,可以继承任意的内置元素
第三个可选参数,需要解释下,我们注册的自定义元素分为两类。
第一种是独立的元素,不继承其他内置的html元素,此时,define
函数不传递第三个参数,元素的类继承自HTMLElment
类。这样注册的自定义元素,使用方式简单,像普通的html元素一样,例如:<element-a />
第二种是继承自某个内置的html元素,例如p
。此时,第三个参数应该是{ extends: 'p' }
。同时元素的类也应该继承HTMLParagraphElement
类。使用方式是<p is="element-a" />
或者在js中document.createElement("p", { is: "element-a" })
。
其中自定义元素的类是最重要的部分,我们会在内部定义它的结构、样式和行为。常见结构如下:
class ElementA extends HTMLElement { constructor() { // 必须首先调用 super 方法 super(); // 元素的功能代码写在这里 // ... } connectedCallback() { // 自定义元素首次插入文档dom时调用 // 相较于constructor只会执行一次,这个生命周期每次将节点连接到dom时都会调用 // 可能会执行多次(比如同一个自定义元素remove, append多次) } disconnectedCallback() { // 自定义元素从文档中删除时,调用 } adoptedCallback() { // 自定义元素移动到新的文档 // 比如使用 adoptNode 方法在多iframe下移动元素 } attributeChangedCallback(name, oldVal, newVal) { // 属性变更时调用:三个参数对应属性名,旧值,新值 } }
在自定义元素类中定义内容需要借助shadow-dom
接口的能力,它提供了封装的能力,将标记结构、样式和行为隐藏到一个独立的dom中,我们操作shdaow-dom
和操作常规dom一样(新添加子节点、修改属性等
),但是在shadow-dom
中的元素和外部的元素互不影响,不能通过document.querySelector
方法拿到内部的元素,外部的css样式也不会影响shadow-dom中定义的元素。我们会在里面定义自定义元素的结构,最后将其附加到常规的dom树中。
浏览器内置的一些html元素也有使用它的功能,例如:video input-range
等,在 Chrome 中,开发者可以启用开发者工具的Show user agent shadow DOM
选项,就能看到这些隐藏的结构。
shadow-dom
和dom的关系如下图所示:
shadow host
:一个常规的dom节点,是shadow-dom
的挂载节点,比如我们的自定义元素shadow tree
:shadow-dom内部的dom树shadow boundary
:shadow-dom结束的地方,也是常规dom开始的地方shadow root
: shadow-tree
的根节点在自定义元素中我们通过Element.attachShadow
将一个shadow root
附加到任意元素上:
const shadowRoot = elementRef.attachShadow({mode: 'open'})
// 参数mode有两个值
// open表示可以通过element.shadowRoot访问shadow-dom
// closed表示不可以从外部获取shadow dom(例如内置元素video)
接着我们就可以为自定义元素添加内容:
const para = document.createElement('p')
para.innerHTML = '这是我的自定义元素'
shadowRoot.appendChild(para)
然后可以使用多种方式给shadow-dom
添加样式:
1.创建style元素
const style = document.createElement('style');
style.textContent = `
p {
color: #ccc;
}
`
shadowRoot.appendChild( style )
2.通过link元素使用外部的样式
const linkElem = document.createElement('link')
linkElem.setAttribute('rel', 'stylesheet')
linkElem.setAttribute('href', 'style.css')
shadow.appendChild(linkElem)
3.使用template,在template中加入一个style节点
最后也可以像常规dom一样设置一些交互事件,甚至定制一些专属的属性,例如我们自定义一个card元素,通过text属性指定card的内容:
<custom-card text="这是我的card组件" />
<script>
class Card extends HTMLElement {
constructor() {
super()
const shadowRoot = this.attachShadow({ mode: 'open' })
const text = this.getAttribute('text')
const p = document.createElement('p')
p.innerHTML = text
shadowRoot.appendChild(p)
}
}
customElements.define('custom-card', Card)
</script>
最后介绍下模板和slot
的使用,上面的方式定义样式和页面结构太麻烦,也不利于复用,我们可以切换为模板和slot
的方式,
我们可以先在template中定义内容和样式,然后添加到shadow dom中:
class extends HTMLElement {
constructor() {
super();
let template = document.getElementById('element-tmp')
let templateContent = template.content
const shadowRoot = this.attachShadow({mode: 'open'})
.appendChild(templateContent.cloneNode(true))
}
}
另外开发者可以通过slot插槽
的方式来传递自定义组件需要的内容(类似于vue
),灵活度更高,同时插槽中的内容会受到外部样式的影响。插槽分为命令插槽和默认插槽。
// 相同名称的多个插槽内容会被放在一起 <slot-exp> <div>未命名插槽内容1</div> <div>未命名插槽内容2</div> <div slot="content-a">content-a</div> <div slot="content-a">content-a</div> </slot-exp> <template id="slot-exp--tmp"> <div class="slot-exp"> <div> <h2>未命名插槽:</h2> <slot /> </div> <div> <h2>具名插槽:</h2> <slot name="content-a" /> </div> <slot name="content-b">插槽 content-b 默认填充</slot> </div> </template> <script> class SlotExp extends HTMLElement { constructor() { super() this.attachShadow({ mode: 'open' }) const tmp = document .getElementById('slot-exp--tmp') .content this.shadowRoot.appendChild( tmp.cloneNode(true) ) } } customElements.define('slot-exp', SlotExp) </script>
开发者可以到can i use搜索web component
查看支持程度,支持度还不错。对于一些还未支持的浏览器,也有polyfills使用。
相较于目前流行的react、vue、ng
等前端框架,web component是浏览器原生提供的不添加任何依赖的组件封装方式,同时提供了一个隔离的运行环境,目前流行的微前端框架的实现方式之一就是借助了web component
的隔离能力。还可以到https://www.webcomponents.org/
查看一些开源的web component
。
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。