当我将 Shadow DOM 添加到自定义元素时......已经声明的非阴影内容(Light DOM)会消失到哪里?

When I add Shadow DOM to a custom element... where does the already declared non-shadow content (Light DOM) disappear to?

TLDR: 一旦我 define() 一个 自定义元素 影子 DOM,在同一元素中声明的 Light DOM 将从浏览器视口中消失。

为什么 Light DOMCustom Element 中不再显示?


我正在学习/试验 Custom ElementsShadow DOM

我注意到如果我有以下 Custom Element 而没有 任何 Shadow DOM,它会起作用:

<my-company>&copy; 2020, </my-company>

但是如果我 然后 通过 Shadow Dom...

添加自定义内容到 Custom Element

class myCompany_Element extends HTMLElement {

  constructor() {
    super();
    this.root = this.attachShadow({mode: "open"});
  }

  connectedCallback() {

    this.root.textContent += 'Cyberdyne Systems';
  }
}

customElements.define('my-company', myCompany_Element);
<my-company>&copy; 2020, </my-company>

原始硬编码内容消失。 (即使它在 DOM 检查器中仍然可见。)

我期待:

© 2020, Cyberdyne Systems

这里发生了什么?

这是否意味着不可能

而且我只能有:

或者 Custom Element 没有 Shadow DOM 是可能的吗?

据我的实验和进一步阅读可以看出,这就是正在发生的事情:

通过在 class 定义中调用 attachShadow(),我们明确确定元素 成为 Shadow Host 当它是 define()-d:

constructor() {
  super();
  this.root = this.attachShadow({mode: "open"});
}

一旦元素正式成为 Shadow HostLight DOM 将不再显示在视口中:

  • Shadow Host 将不会显示 Light DOM 已经在 HTML
  • 中声明
  • Shadow Host 将不会显示 Light DOM 稍后添加,通过 Javascript

进一步确认:

By default, if an element has shadow DOM, the shadow tree is rendered instead of the element's children

Source: https://polymer-library.polymer-project.org/3.0/docs/devguide/shadow-dom


结论:

恢复元素的 Light DOM 子元素的标准(也是唯一的?)方法是使用命名 <slot>-s,在此案例:

class myCompany_Element extends HTMLElement {

  constructor() {
    super();
    this.root = this.attachShadow({mode: "open"});
  }

  connectedCallback() {
 
    this.root.innerHTML += '<slot name="template"></slot>';
    this.root.innerHTML += 'Cyberdyne Systems';
  }
}

customElements.define('my-company', myCompany_Element);
<my-company><span slot="template">&copy; 2020, </span></my-company>

这是一个不需要 slots 的适用于您的用例的简单解决方案:

class myCompany_Element extends HTMLElement {
    constructor() {
        super()
        this.root = this.attachShadow({ mode: 'open' })
    }

    connectedCallback() {
        // added line below
        this.root.textContent += this.textContent
        this.root.textContent += 'Cyberdyne Systems'
    }
}

customElements.define('my-company', myCompany_Element)
<my-company>&copy; 2020, </my-company>

如果需要,您也可以在设置 this.root.textContent 后将 this.textContent 归零为 ''。据我所知,使用 Chrome 开发工具,这样做对可访问性没有影响,但从开发人员体验的角度来看可能是可取的。