如何在没有 attachShadow 的情况下创建自定义元素?

假设我有这样的代码:


class MyElem extends HTMLElement {

  constructor() {

    super();

    

    let templateContent = document.getElementById('template-elem').content;

    this.innerHTML = templateContent.cloneNode(true);

  }

}


window.customElements.define('my-elem', MyElem);

<template id="template-elem">

  <div class="a">

    <div class="b">b</div>

    <div class="c">c</div>

  </div>

</template>


<my-elem></my-elem>


为什么这不起作用?在 Chrome 检查器中,自定义元素内部没有 HTML。我也试过这样做:


this.append(templateContent.cloneNode(true)); 

但这也导致了一个空的 HTML 树。


所有教程都提到使用影子 DOM,如下所示:


this.attachShadow({mode: 'open'}).appendChild(templateContent.cloneNode(true));

虽然这有效,但它会强制您将 Shadow DOM 用于您的自定义元素。有没有办法在不需要使用 Shadow DOM 的情况下将模板的 HTML 附加到您的自定义元素?我更愿意在我的小用例中使用全局 CSS 样式。


小唯快跑啊
浏览 84回答 2
2回答

眼眸繁星

你正陷入多个陷阱,就像每个人在他们的第一次组件冒险中一样。自定义元素(严格来说只有带有shadowDOM 的元素才是 Web 组件)具有生命周期阶段和回调。你想在阶段添加 DOM 内容constructor;但是这个阶段还没有 DOM 元素。只有在里面connectedCallback才能添加DOM内容。有了shadowDOM 就另当别论了,它的“DocumentFragment”在 中可用constructor,你可以设置内容,但它还不是DOM元素!告诉connectedCallback您自定义元素何时附加到 DOM。模板内容是一个 DocumentFragment,但您.innerHTML需要一个字符串。由于(在您的使用中)<template> 是一个 DOM 元素,您可以阅读它的 innerHTML(见下文)所以,是的,没有shadowDOM的自定义元素是可能的:您将看到两次<template>内容,演示了添加内容的 2 种方式。<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>这constructor是您准备元素的地方这constructor也会在您执行时运行document.createElement("my-element")。connectedCallback当您的元素添加到 DOM 时运行如果您不指定方法,则运行其 Class 父类中的方法,因此在上面的代码中,constructor将执行 HTMLElement 中的(默认)方法。这就是为什么您需要super()在自己的constructor... 中执行constructor来自 HTMLElement 的原因。笔记:constructor(){ let template = document.getElementById("MY-ELEMENT").content.cloneNode(true); super().attachShadow({mode:"open").append(template);}是完全有效的代码;说“超级需要先运行”的谷歌文档是错误的。您需要运行才能访问super() 元素自己的范围this这就是为什么我更喜欢:constructor(){ // do anything you want here, but you can not use 'this' super() // Sets AND Returns 'this'   .attachShadow({mode:"open") // both Sets AND Returns this.shadowRoot   .append(document.getElementById(this.nodeName).content.cloneNode(true));}注意append()在 IE 中不可用;所以 oldskool 程序员不会知道它的多功能性:https://developer.mozilla.org/en-US/docs/Web/API/Element/append当您的组件冒险将涉及类继承时;你调用父方法:connectedCallback(){  super.connectedCallback()}

慕尼黑的夜晚无繁华

自定义元素最简单的实现是:class MyComponent extends HTMLElement {&nbsp; &nbsp; connectedCallback() {&nbsp; &nbsp; &nbsp; &nbsp; this.innerHTML = `<div>Hello world</div>`&nbsp; &nbsp; }}customElements.define('my-component', MyComponent)my-component {&nbsp; display: block;&nbsp; border: 1px dotted #900}<my-component></my-component>但是,如果不使用 Shadow DOM,则无法封装 CSS,而必须通过外部样式表来为组件设置样式。使用Shadow DOM编写组件的最简单方法如下所示:class MyOtherComponent extends HTMLElement {&nbsp; &nbsp; constructor() {&nbsp; &nbsp; &nbsp; &nbsp; super()&nbsp; &nbsp; &nbsp; &nbsp; this.shadow = this.attachShadow({ mode: "open" })&nbsp; &nbsp; }&nbsp; &nbsp; connectedCallback() {&nbsp; &nbsp; &nbsp; &nbsp; this.shadow.innerHTML = `&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <style>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; :host {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; display: block;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; border: 1px dotted #900&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </style>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <div class="component">Hello World!</div>&nbsp; &nbsp; &nbsp; &nbsp; `&nbsp; &nbsp; }}customElements.define('my-other-component', MyOtherComponent)<my-other-component></my-other-component>这样,你有更多的开销,但组件是真正封装的。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript