为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

小唯快跑啊 2023-06-15 16:47:41
假设我有这样的代码: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 样式。
查看完整描述

2 回答

?
眼眸繁星

TA贡献1873条经验 获得超9个赞

你正陷入多个陷阱,就像每个人在他们的第一次组件冒险中一样。

  1. 自定义元素(严格来说只有带有shadowDOM 的元素才是 Web 组件)具有生命周期阶段和回调。
    你想在阶段添加 DOM 内容constructor;但是这个阶段还没有 DOM 元素。
    只有在里面connectedCallback才能添加DOM内容。
    有了shadowDOM 就另当别论了,它的“DocumentFragment”在 中可用constructor,你可以设置内容,但它还不是DOM元素!告诉connectedCallback您自定义元素何时附加到 DOM。

  2. 模板内容是一个 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()

}


查看完整回答
反对 回复 2023-06-15
?
慕尼黑的夜晚无繁华

TA贡献1864条经验 获得超6个赞

自定义元素最简单的实现是:


class MyComponent extends HTMLElement {

    connectedCallback() {

        this.innerHTML = `<div>Hello world</div>`

    }

}


customElements.define('my-component', MyComponent)

my-component {

  display: block;

  border: 1px dotted #900

}

<my-component></my-component>


但是,如果不使用 Shadow DOM,则无法封装 CSS,而必须通过外部样式表来为组件设置样式。


使用Shadow DOM编写组件的最简单方法如下所示:


class MyOtherComponent extends HTMLElement {

    constructor() {

        super()

        this.shadow = this.attachShadow({ mode: "open" })

    }


    connectedCallback() {

        this.shadow.innerHTML = `

            <style>

                :host {

                  display: block;

                  border: 1px dotted #900

                }

            </style>

            <div class="component">Hello World!</div>

        `

    }

}


customElements.define('my-other-component', MyOtherComponent)

<my-other-component></my-other-component>

这样,你有更多的开销,但组件是真正封装的。



查看完整回答
反对 回复 2023-06-15
  • 2 回答
  • 0 关注
  • 76 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信