Svelte: установить фокус на щелевой элемент в пользовательском веб-компоненте - PullRequest
0 голосов
/ 23 января 2020

В настоящее время я создаю пользовательскую библиотеку веб-компонентов с помощью Svelte.

Я закончил выпадающий компонент 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. Хотя вы не можете поместить директиву привязки непосредственно в элемент слота (вы можете разместить атрибуты в слоте), я смог привязать родительский тег 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>

Я также могу успешно изменить атрибуты элементов в объекте параметров и увидеть изменения в DOM. Таким образом, нет никаких проблем, когда дело доходит до «захвата» выделенного элемента и изменения его атрибутов. Однако следующее не будет работать из родительского компонента для фокусировки выделенного элемента:

options[0].focus();

Это не выдает никаких ошибок, оно просто ничего не делает, что я могу DISCERN. Как уже упоминалось, я могу переключаться между параметрами, поэтому они могут получать фокус в обычном сценарии вкладок. Мне кажется, что только через JavaScript я не могу назначить фокус.

Любые советы и / или общие рекомендации Svelte c при работе с пользовательскими веб-элементами и слот-контентом будут высоко оценены. Большое спасибо.

Ответы [ 2 ]

0 голосов
/ 24 января 2020

Я думаю, что Бенни Хинрикс предоставил элегантное решение (плюс работающий REPL !), Которое включает в себя меньше обходных путей, чем приведенный ниже подход, который я также обнаружил.

Как ни странно, фокусировка света Элемент DOM (через опции [0]), как описано в моем первом посте, не привел к установке фокуса, , но сверление в тени Root светлого элемента DOM позволило мне сфокусировать div класс, который окутывает мой вариант. Это успешно назначило фокус одному из элементов слота, только это был неправильный элемент ...

Кажется, есть проблема порядка стека (возможно, указанная c для Svelte), потому что оборачивая фокус в функцию setTimeout (вы можете использовать 0 миллисекунд), затем устанавливаете фокус на правильный элемент в массиве, в данном случае это элемент в позиции 0, то есть первый выпадающий список в моем списке.

setTimeout(function() {
        options[0].shadowRoot.querySelector(".option-container").focus();
}, 0);
0 голосов
/ 24 января 2020

Одна вещь, которую я делал в прошлом, заключалась в том, что я скрыл родительский тег, а затем собрал все значения параметров и поместил их в новые теги, используя #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>

Вот ссылка на весь REPL

...