Rya*_*hel 1 html javascript web-component shadow-dom
假设我有一些这样的代码:
class MyElem extends HTMLElement {
constructor() {
super();
let templateContent = document.getElementById('template-elem').content;
this.innerHTML = templateContent.cloneNode(true);
}
}
window.customElements.define('my-elem', MyElem);Run Code Online (Sandbox Code Playgroud)
<template id="template-elem">
<div class="a">
<div class="b">b</div>
<div class="c">c</div>
</div>
</template>
<my-elem></my-elem>Run Code Online (Sandbox Code Playgroud)
为什么这不起作用?在 Chrome 检查器中,自定义元素内部没有 HTML。我也试过这样做:
this.append(templateContent.cloneNode(true));
Run Code Online (Sandbox Code Playgroud)
但这也导致了一个空的 HTML 树。
所有教程都提到使用 shadow DOM,如下所示:
this.attachShadow({mode: 'open'}).appendChild(templateContent.cloneNode(true));
Run Code Online (Sandbox Code Playgroud)
虽然这样做有效,但它会强制您将 Shadow DOM 用于您的自定义元素。有没有办法在不需要使用 Shadow DOM 的情况下将模板的 HTML 附加到您的自定义元素?我更喜欢在我的小用例中使用全局 CSS 样式。
你掉进了多个陷阱,就像每个人第一次组件冒险一样。
自定义元素(严格来说只有带有shadowDOM 的元素是 Web 组件)具有生命周期阶段和回调。
这个图:https : //andyogo.github.io/custom-element-reactions-diagram/是必须要理解的。
你想在 constructor 阶段中添加DOM内容;但是在这个阶段还没有 DOM 元素。
只有在connectedCallbackDOM 内容才能被添加。
使用shadowDOM 这是另一回事,它的“DocumentFragment”在 中可用 constructor ,您可以设置内容,但它还不是DOM 元素!在connectedCallback当您的自定义要素是附加到DOM告诉你。
模板内容是一个 DocumentFragment,但您.innerHTML需要一个字符串。
由于(在您的使用中)<template> 是一个 DOM 元素,您可以读取它的 innerHTML(见下文)
所以,是的,没有shadowDOM 的自定义元素是可能的:
您将看到两次<template>内容,演示了两种添加内容的方式。
<script>
customElements.define("my-element", class extends HTMLElement {
connectedCallback() {
let template = document.getElementById(this.nodeName);
this.innerHTML = template.innerHTML;
this.append(template.content.cloneNode(true))
}
})
</script>
<template id="MY-ELEMENT">
Hello, I am an Element!
</template>
<my-element></my-element>Run Code Online (Sandbox Code Playgroud)
这 constructor 是您准备元素的地方
这 constructor 也会在您执行时运行document.createElement("my-element")。
在connectedCallback当你的元素被添加到DOM运行
如果你没有指定方法,它的父类中的方法就会运行,所以在上面的代码中 constructor ,HTMLElement 中的(默认)被执行。
这就是为什么您需要super()在自己的 constructor ... 中执行 constructor from HTMLElement。
笔记:
constructor(){
let template = document.getElementById("MY-ELEMENT").content.cloneNode(true);
super().attachShadow({mode:"open").append(template);
}
Run Code Online (Sandbox Code Playgroud)
是完全有效的代码;谷歌文档说“超级需要先运行”是错误的。
您需要先运行,super() 然后才能访问Elements 自己的作用域this
这就是为什么我更喜欢:
constructor(){
// do anything you want here, but you can not use 'this'
super() // returns 'this'
.attachShadow({mode:"open") // both Sets AND Returns this.shadowRoot
.append(document.getElementById(this.nodeName).content.cloneNode(true));
}
Run Code Online (Sandbox Code Playgroud)
当你的组件冒险将涉及到类继承时;
你调用父方法:
connectedCallback(){
super.connectedCallback()
}
Run Code Online (Sandbox Code Playgroud)