为什么我的影子dom破坏了我的自定义元素?

问题描述 投票:0回答:1

这里是自定义元素的小提琴演示:https://jsfiddle.net/c4bLo097/5/

这是小提琴中的代码:

JavaScript:
window.customElements.define('test-element', class TestElement extends HTMLElement {
    constructor() {
    super()

    let contents = `
      <style>
        :host {
          display: block;
        }
        :host([hidden]) {
          display: none;
        }
      </style>`

    // convert string to nodes
    let template = document.createElement('template')
    template.innerHTML = contents

    // create shadow
    this.attachShadow({mode: 'open'})

    // insert nodes
    this.shadowRoot.appendChild(template.content.cloneNode(true))
  }
})


HTML:
<test-element>
  This element should have a natural height.

  <div style="height: 300px;"></div>

  I should be able to see this text on a green background.
</test-element>


CSS:
test-element {
  width: 200px;
  background: green;
}

如果使用开发者工具检查<custom-element>,则应该看到阴影存在。但是我的元素无法正确显示其高度。

这里是我要达到的目标的一个例子:https://jsfiddle.net/9483s1qb/2/

谢谢

javascript css web-component shadow custom-element
1个回答
0
投票

当添加shadowDOM时,元素的内容将变为“ lightDOM”。.

它不再是您的ShadowDOM的不再显示在主DOM中not的一部分。

作为Supersharp explained in 2017

Light DOM只是HTML元素内的普通DOM树。

该术语仅在Web组件(带有Shadow DOM的自定义元素)的上下文中使用我想将普通DOM与Shadow相对地重新定义为Light

The WHATWG specs称为Shadowroot主机的节点树轻树

影子DOM是添加的DOM,用于恢复,掩盖或替换普通DOM,如the article from Google中所述。

您必须自己将lightDOM内容传输到shadowDOM:

customElements.define('my-element', class extends HTMLElement {
    constructor() {
    super()
    //create shadowDOM (thus creating lightDOM) and append Template
    this.attachShadow({mode: 'open'})
        .append(document.getElementById(this.nodeName).content.cloneNode(true))
  }
  connectedCallback(){
    //append content from lightDOM
    this.shadowRoot.append(...this.querySelectorAll('DIV'));
  }
})
my-element{
  border: 1px dashed blue;
}
<template id="MY-ELEMENT">
  <style>
    :host {
      display: block;
      font-size:20px;
    }
    h4{
      background:yellow;
      margin: .5em 0;
    }
    div{
      background:lightcoral;
    }
  </style>
  <h4><slot name="title"></slot></h4>
</template>

<my-element>
  <!-- begin lightDOM because my-element has shadowDOM -->
  <span slot="title">whole SPAN is slotted</span>
  <div>I am appended</div>
  <div>appended too</div>
  <p>I remain (invisible) in lightDOM</p>
  <!-- end lightDOM -->
</my-element>

<my-element>
  <!-- begin lightDOM because my-element has shadowDOM -->
  <span slot="title">slotted too</span>
  <div>appended again</div>
  I remain (invisible) in lightDOM
  <!-- end lightDOM -->
</my-element>

注意:

  • 模板是cloned

    ] >>
  • connectedCallback中的[[append

    的内容,如果您想将原始内容保留在lightDOM中(例如,将其用作数据存储区)您必须像使用template一样克隆它。slot="title"
  • 移动整个span(包括跨度!)到shadowDOM中其插槽的位置
  • 尝试一下:

    • 未命名
    • 会发生什么:<slot></slot>
  • 如果将<span>更改为<div>

  • 注意!!浏览器的行为有所不同!
  • 当尚未实例化(主)DOM时,您可能会[[require setTimeout中的connectedCallback

    connectedCallback() { let savedHTML = this.outerHTML; //append content from lightDOM const append = (selector) => this.shadowRoot.append(...this.querySelectorAll(selector), savedHTML); if (this.outerHTML.includes("timeout")) setTimeout(() => append('DIV')) else append('DIV'); }

    JSFiddle操场:https://jsfiddle.net/CustomElementsExamples/bzvLcxfe/

    在[[first

    中黄色元素DIV附加
      无 [setTimeout
    ] >>
  • second中的黄色元素DIV附加了with

    [setTimeout
  • ] >>
  • outerHTML(在[[in connectedCallback中是已知的])附加在两个元素中。

  • 在Chrome \ Edge \ Opera中的结果:
  • lightDOM是

    not

    可用,需要setTimeout才能将代码延迟到事件循环结束并且lightDOM可用。“”
  • 在FireFox中的结果:

      lightDOM
    • is

    可用,no setTimeout是必需的“”

    Safari的结果:

    • [我还不知道,请告诉我
    © www.soinside.com 2019 - 2024. All rights reserved.