如何为插槽中的所有插槽表重复外部 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 个元素,并且包装到列表中将发生在组件本身的内部。
更改代码以便在模板中的 <ul>
中有一个 <li>
会失败,因为所有可插入元素都进入相同的 <li>
元素。
在 <ul>
内的 <slot>
上设置 role="listitem"
失败,因为在 <slot>
上设置的属性未复制到可槽中。
向 <slot>
添加 slotchange
事件侦听器并为每个分配的节点设置 role="listitem"
确实有效,但这意味着 Web 组件与提供节点,这似乎不合适。
进入 slotchange
事件并试图弄乱分配的节点,因此我可以动态地将它们包裹在新创建的 <li>
元素周围,需要我将它们从他们在 DOM 中的位置。因此它不仅会扰乱 user-provided 标记,还会触发新的 slotchange
事件。
有没有其他方法可以在不泄露自定义元素的实现细节的情况下做到这一点?
在搜索了一下其他人似乎是如何使用网络组件之后,我找到了一个部分可以接受的解决方案:使用 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
。我不知道这是浏览器特有的错误,还是我不太了解的东西的副作用,但至少它似乎工作正常。
下图显示了无障碍树:
原生<ul>
和<li>
列表
我的解决方案,在 <li>
元素上没有 role="listitem"
我的解决方案,在 <li>
元素上使用 role="listitem"
如果有人知道有关此行为的任何信息,我很想知道,但现在我会接受此解决方案,因为:
避免泄露实现细节;从库的角度来看,两者都可以在不影响用户代码的情况下进行内部更改
它避免了每次内容更改时必须 运行 的任何 JavaScript 魔法,用户可以添加和删除 <x-list-item>
并且浏览器会完成所有工作
它产生了可接受的可访问性树(这与本机 <ul>
和 <li>
之间存在细微差异,但它们的差异不足以让我认为它一个问题)
我想要一个接受 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 个元素,并且包装到列表中将发生在组件本身的内部。
更改代码以便在模板中的
<ul>
中有一个<li>
会失败,因为所有可插入元素都进入相同的<li>
元素。在
<ul>
内的<slot>
上设置role="listitem"
失败,因为在<slot>
上设置的属性未复制到可槽中。向
<slot>
添加slotchange
事件侦听器并为每个分配的节点设置role="listitem"
确实有效,但这意味着 Web 组件与提供节点,这似乎不合适。进入
slotchange
事件并试图弄乱分配的节点,因此我可以动态地将它们包裹在新创建的<li>
元素周围,需要我将它们从他们在 DOM 中的位置。因此它不仅会扰乱 user-provided 标记,还会触发新的slotchange
事件。
有没有其他方法可以在不泄露自定义元素的实现细节的情况下做到这一点?
在搜索了一下其他人似乎是如何使用网络组件之后,我找到了一个部分可以接受的解决方案:使用 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
。我不知道这是浏览器特有的错误,还是我不太了解的东西的副作用,但至少它似乎工作正常。
下图显示了无障碍树:
原生
<ul>
和<li>
列表我的解决方案,在
<li>
元素上没有role="listitem"
我的解决方案,在
<li>
元素上使用role="listitem"
如果有人知道有关此行为的任何信息,我很想知道,但现在我会接受此解决方案,因为:
避免泄露实现细节;从库的角度来看,两者都可以在不影响用户代码的情况下进行内部更改
它避免了每次内容更改时必须 运行 的任何 JavaScript 魔法,用户可以添加和删除
<x-list-item>
并且浏览器会完成所有工作它产生了可接受的可访问性树(这与本机
<ul>
和<li>
之间存在细微差异,但它们的差异不足以让我认为它一个问题)