如何为插槽中的所有插槽表重复外部 DOM?

How to repeat outer DOM for all the slottables in a slot?

我想要一个接受 N children 并以列表格式显示它们的 Web 组件。我发现我可以声明 N 个具有相同名称的插槽,它们将被添加为彼此的兄弟姐妹,如下所示:

window.customElements.define('x-list', class extends HTMLElement {
  constructor () {
    super();
    const template = document.querySelector('#x-list').content;
    const shadow = this.attachShadow({ mode: 'open' });
    shadow.appendChild(template.cloneNode(true));
  }
});
<x-list>
  <li slot="item">Item 1</li>
  <li slot="item">Item 2</li>
  <li slot="item">Item 3</li>
</x-list>

<template id="x-list">
  <ul>
    <slot name="item">Items go here</slot>
  </ul>
</template>

效果不错。但我不想透露实施细节,所以我一直在寻找其他方法。理想情况下,使用该组件的人只需要提供 N 个元素,并且包装到列表中将发生在组件本身的内部。

有没有其他方法可以在不泄露自定义元素的实现细节的情况下做到这一点?

在搜索了一下其他人似乎是如何使用网络组件之后,我找到了一个部分可以接受的解决方案:使用 2 个网络组件,而不是 1 个;一个用于列表,一个用于列表项。

或片段形式:

window.customElements.define('x-list', class extends HTMLElement {
  constructor () {
    super();
    const template = document.querySelector('#x-list').content;
    const shadow = this.attachShadow({ mode: 'open' });
    shadow.appendChild(template.cloneNode(true));
  }
});

window.customElements.define('x-list-item', class extends HTMLElement {
  constructor () {
    super();
    const template = document.querySelector('#x-list-item').content;
    const shadow = this.attachShadow({ mode: 'open' });
    shadow.appendChild(template.cloneNode(true));
  }
});
<template id="x-list">
  <ul>
    <slot></slot>
  </ul>
</template>

<template id="x-list-item">
   <li role="listitem">
     <slot>List item</slot>
   </li>
</template>

<x-list>
  <x-list-item>Item 1</x-list-item>
  <x-list-item>Item 2</x-list-item>
  <x-list-item>Item 3</x-list-item>
</x-list>

除了 x-list-item 的模板实际上需要将 role="listitem" 属性添加到 <li> 元素之外,它工作正常。

如果我不添加 role 属性,Firefox 辅助工具将拒绝将 <li> 解释为 listitem,并将它们标记为 text container。我不知道这是浏览器特有的错误,还是我不太了解的东西的副作用,但至少它似乎工作正常。

下图显示了无障碍树:

  1. 原生<ul><li>列表

  2. 我的解决方案,在 <li> 元素上没有 role="listitem"

  3. 我的解决方案,在 <li> 元素上使用 role="listitem"

如果有人知道有关此行为的任何信息,我很想知道,但现在我会接受此解决方案,因为:

  1. 避免泄露实现细节;从库的角度来看,两者都可以在不影响用户代码的情况下进行内部更改

  2. 它避免了每次内容更改时必须 运行 的任何 JavaScript 魔法,用户可以添加和删除 <x-list-item> 并且浏览器会完成所有工作

  3. 它产生了可接受的可访问性树(这与本机 <ul><li> 之间存在细微差异,但它们的差异不足以让我认为它一个问题)