苗条:将焦点设置为自定义Web组件中的广告位元素

时间:2020-01-22 22:32:45

标签: focus web-component shadow-dom svelte slot

我目前正在使用Svelte构建自定义Web组件库。

我已经完成一个select-options下拉菜单组件,该组件可以接受嵌套的带槽内容组成下拉菜单选项。它对鼠标用户没有任何已知问题,可以像这样实现:

<custom-select label="My Custom Select Element">
        <custom-option value="1">Option 1</custom-option>
        <custom-option value="2">Option 2</custom-option>
        <custom-option value="3">Option 3</custom-option>
</custom-select>

我现在正在研究组件的可访问性,并且需要实现“陷阱重点”。在不深入研究实现陷阱焦点的各种方式的情况下,我试图完成一个简单的测试,即将焦点分配给父组件中的一个插槽元素。所有插入的元素都具有tabindex =“ 0”,我可以毫无问题地浏览它们。

我可以使用Svelte中的绑定成功“抓取”我要关注的元素。虽然您不能直接在slot元素上放置绑定指令(您可以可以在slot上放置属性),但是我能够像这样绑定到父span标签:

<span bind:this={slotObj}>
        <slot />
</span>

然后,我可以使用一些JavaScript深入绑定父对象,并将开槽的元素分配到名为“ options”的对象中:

let slot = slotObj.children[0];
options = slot.assignedElements();

如果我要控制台记录选项对象中的第一个元素,则会看到预期的结果:

console.log(options[0]); // <custom-option value="1">Option 1</custom-option>

我还可以成功修改options对象中元素的属性,并查看DOM中的更改。因此,在“抓取”带槽元素并更改其属性时没有问题。但是,以下操作将不能在父组件内部工作以集中放置槽式元素:

options[0].focus();

这不会引发任何错误,它只会执行我无法识别的任何操作。如前所述,我能够浏览选项,因此它们 能够在常规选项卡方案中获得关注。我似乎只能通过JavaScript来分配焦点。

在处理自定义Web元素和广告位内容时,任何Svelte的特定建议和/或一般建议将不胜感激。非常感谢。

2 个答案:

答案 0 :(得分:0)

我过去做的一件事是我隐藏了父标签,然后我抓住了选项的所有值,然后使用#each将它们放在新标签中。我将相关的事件侦听器放在#each块的父级上。

App.svelte

<MultiSelect>
  <option value="MS">Malay</option>
  <option value="RU">Russian</option> 
  <option value="TH">Thai</option>
</MultiSelect>
MultiSelect.svelte

<script>
  let slot, options = [], selected = {};
  onMount(() => {
    slot.querySelectorAll('option').forEach(o => {
      o.selected && !value.includes(o.value) && (value = [...value, o.value]);
      options = [...options, {value: o.value, name: o.textContent}]
    });
</script>

<ul class="options" on:mousedown|preventDefault={handleOptionMousedown}>
  {#each filtered as option}
    <li class:selected={selected[option.value]} class:active={activeOption === option} data-value="{option.value}">{option.name}</li>
  {/each}
</ul>

<select bind:this={slot} type="multiple" class="hidden"><slot></slot></select>

Here's the link to the whole REPL

答案 1 :(得分:0)

我认为Benny Hinrichs提供了一种优雅的解决方案(加上有效的REPL!),其解决方法比我发现也可以使用的以下方法少。

奇怪的是,如我在开幕文章中所述,聚焦轻型DOM元素(通过options [0])并没有导致设置焦点,但是钻入了轻型DOM元素的shadowRoot让我专注于包装我的选择的div类。这成功地将焦点分配给了其中一个空位元素,只是它是错误元素...

似乎存在堆栈顺序问题(可能特定于Svelte),因为将焦点包装在setTimeout函数中(您可以使用0毫秒),然后将焦点设置到数组中的正确元素,在这种情况下,元素位于适当位置0,即我列表中的第一个下拉选项。

setTimeout(function() {
        options[0].shadowRoot.querySelector(".option-container").focus();
}, 0);