0

我想要一个接受 N 个孩子的 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 个元素,并且包装成一个列表将发生在组件本身的内部。

  • 更改代码以使模板中有一个<li>内部的<ul>失败微不足道,因为所有可插槽都进入同一个<li>元素。

  • role="listitem"<slot>内部设置<ul>失败,因为在 上设置的属性<slot>没有复制到可插槽中。

  • 为每个分配的节点添加slotchange事件侦听器<slot>和设置role="listitem"确实有效,但这意味着 Web 组件正在与提供的节点混淆,这似乎不合适。

  • 进入slotchange事件并试图弄乱分配的节点,以便我可以动态地将它们包装在新创建的<li>元素周围,需要我将它们从它们在 DOM 中的位置中删除。因此,它不仅会与用户提供的标记混淆,而且还会触发新的slotchange事件发生。

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

4

1 回答 1

0

在搜索了一些其他人似乎如何使用 Web 组件之后,我找到了一个部分可接受的解决方案:使用 2 个 Web 组件,而不是 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 Accessibility Tools 拒绝将其解释<li>listitem,并将它们标记为text container。我不知道这是特定于浏览器的错误,还是我不太了解的东西的副作用,但至少它似乎工作正常。

下图显示了可访问性树:

  1. 一个本地人<ul><li>列表

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

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

生成的 3 个不同列表的可访问性树

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

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

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

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

于 2020-01-07T15:24:52.467 回答