影子 dom 内的重复命名插槽不起作用

duplicated named slot inside shadow dom not working

我有一个看起来像这样的自定义元素:

class RepeatMe extends HTMLElement {
    constructor() {
        super();
        this.attachShadow({ mode: 'open' });

        let slot = document.createElement('slot');
        slot.setAttribute('name', 'bar');
        this.shadowRoot.append(slot);

        slot = document.createElement('slot');
        slot.setAttribute('name', 'content');
        this.shadowRoot.append(slot);

        slot = document.createElement('slot');
        slot.setAttribute('name', 'bar');
        this.shadowRoot.append(slot);
    }
}

window.customElements.define('repeat-me', RepeatMe);

我的使用方式如下:

<repeat-me>
    <div slot="bar">I'm a bar</div>
    <div slot="content">I'm some content</div>
</repeat-me>

我想在阴影dom中重复插槽bar(因为内容在开头和结尾是相同的),但我得到的是只有第一个插槽被渲染,第二个是空的。我想用 shadow dom 插槽做的事情是可能的,还是你知道一些方法来实现这样的事情?

不,插槽是唯一的
并且多个 lightDOM 元素可以插入到同一个 SLOT

将 SLOT 视为您的邮箱;你想让你的邮件总是复制到另一个邮箱吗?

如果您有此要求,则需要一个过滤器来复制电子邮件(或插槽内容)

对于 WebComponents,有 2 个选项可以复制:

  1. <span slot="bar"> 克隆到 shadowRoot

    内的其他(非插槽)DOM 元素
  2. 克隆到新的 lightDOM 元素 <span slot="duplicate_bar1"> 用于新插入的内容

下面的代码有两个选项 slotchange 发生在 <span slot="bar"> 的事件(插槽中的新内容)

  1. slotchange 插槽内容被克隆到 class="duplicate_bar" (let dups = ...)

  2. slotchange 上创建了新的灯 DOM 元素 (let dupslots = ...)

请注意,只有方法 2. 使用 <slot> 功能,您可以使用 :slotted 样式

此代码仅复制内容;它不会清理删除的 SLOT 内容。

<my-element>
  <span slot="bar"> ONE </span>
  <span slot="bar"> TWO </span>
  <span slot="content"> content </span>
</my-element>
<template id="MY-ELEMENT">
  <style>
    ::slotted(*) { background: lightgreen }
  </style>
  slot bar: <slot name="bar"></slot>
  <br> slot: content: <slot name="content"></slot>
  <br>Duplicate in SPAN: <span class="duplicate_bar"></span>
  <br>Duplicate in B:<b class="duplicate_bar"></b>
  <br>duplicate_bar1:<slot name="duplicate_bar1"></slot>
  <br>duplicate_bar2:<slot name="duplicate_bar2"></slot>
</template>
<script>
  customElements.define('my-element', class extends HTMLElement {
    constructor() {
      let template = id => document.getElementById(id).content.cloneNode(true);
      super().attachShadow({mode: 'open'}).append(template(this.nodeName));
      let slotname = "bar";
      let slot = this.shadowRoot.querySelector(`[name="${slotname}"]`);
      slot.addEventListener("slotchange", (evt) => {
        let assigned = slot.assignedNodes();
        let dups = [...this.shadowRoot.querySelectorAll(".duplicate_" + slotname)];
        let dupslots = [...this.shadowRoot.querySelectorAll(`slot[name*="duplicate_bar"]`)];
        assigned.forEach(node => {
          dups.forEach(el => el.append(node.cloneNode(true)));
          dupslots.forEach(duplicateslot => {
            let newNode = node.cloneNode(true);
            newNode.slot = duplicateslot.name; // set BEFORE adding to DOM! otherwise 'bar' slotchange Events triggers on it
            this.append(newNode);
          })
        });
      });
    }
  });
</script>