Как сосредоточиться на вновь добавленных входных данных в Svelte?

Вопрос или проблема

Я использую #each для отображения поля ввода для каждого члена массива tasks. Когда я нажимаю кнопку “Добавить задачу”, новый элемент вставляется в массив, и в цикле #each появляется новое поле ввода.

Как мне сфокусироваться на добавленном поле ввода после нажатия кнопки “Добавить задачу”?

<script>
  let tasks = [];

  function addTask() {
    tasks = [...tasks, { title: "" }];
  }
</script>

{#each tasks as task}
  <input type="text" bind:value={task.title} />
{/each}

<button on:click={addTask}>Добавить задачу</button>

Рич Харрис предлагает более красивое решение


Вы можете использовать use:action:

Аctions — это функции, которые вызываются, когда элемент создается.

Например:

<script>
  let tasks = [];

  function addTask() {
    tasks = [...tasks, { title: "" }];
  }
    
  function init(el){
    el.focus()
  }
</script>

{#each tasks as task}
  <input type="text" bind:value={task.title} use:init />
{/each}

<button on:click={addTask}>Добавить задачу</button>

Вы можете использовать атрибут autofocus:

<script>
  let tasks = [];

  function addTask() {
    tasks = [...tasks, { title: "" }];
  }
</script>

{#each tasks as task}
  <input type="text" bind:value={task.title} autofocus />
{/each}

<button on:click={addTask}>Добавить задачу</button>

Обратите внимание, что вы получите предупреждение о доступности. Это связано с тем, что рекомендации по доступности фактически советуют не делать этого:

Люди с заболеваниями зрения могут испытывать дезориентацию, когда фокус перемещается без их разрешения. Кроме того, автоввод может вызвать проблемы у людей с нарушениями моторики, так как это может создать дополнительные трудности при переходе из области автоввода в другие места на странице.

Решение, использовать ли этот совет, остается за вами!

Вы можете использовать bind:this и tick

Например:

<script>
  import { tick } from 'svelte';

  let tasks = [];

  async function addTask() {
    let newTask = { title: "" };
    tasks = [...tasks, newTask];

    await tick();
    newTask.input.focus();
  }
</script>

{#each tasks as task}
  <input type="text" bind:value={task.title} bind:this={task.input} />
{/each}

<button on:click={addTask}>Добавить задачу</button>

Объяснение преимуществ моего подхода

Что произойдет, если массив tasks изначально не пуст? В этом случае методы autofocus и use:action имеют недостаток в том, что при первоначальном отображении списка фокус находится на последнем поле. Это может быть нежелательно.

Мой подход контролирует фокус только в момент нажатия кнопки “Добавить”.

Ответ или решение

Чтобы сфокусироваться на вновь добавленных полях ввода в Svelte, можно воспользоваться несколькими подходами. Ниже приведены наиболее распространенные методы:

1. Использование директивы use:action

Директивы действий позволяют вам вызывать функции при создании элемента. В данном случае мы можем создать функцию init, которая будет фокусироваться на элементе при его создании.

<script>
  let tasks = [];

  function addTask() {
    tasks = [...tasks, { title: "" }];
  }

  function init(el) {
    el.focus();
  }
</script>

{#each tasks as task}
  <input type="text" bind:value={task.title} use:init />
{/each}

<button on:click={addTask}>Добавить задачу</button>

2. Использование autofocus

Вы также можете использовать атрибут autofocus, чтобы автоматически установить фокус на новом поле ввода. Однако этот подход может быть проблематичным с точки зрения доступности, так как внезапные изменения фокуса могут быть неудобны для пользователей с ограничениями возможностей.

<script>
  let tasks = [];

  function addTask() {
    tasks = [...tasks, { title: "" }];
  }
</script>

{#each tasks as task}
  <input type="text" bind:value={task.title} autofocus />
{/each}

<button on:click={addTask}>Добавить задачу</button>

3. Использование bind:this и tick

Этот метод позволяет получить доступ к элементу ввода и установить на него фокус только после добавления новой задачи. Он более контролируемый, и вы можете избежать проблем с фокусом для уже существующих элементов.

<script>
  import { tick } from 'svelte';

  let tasks = [];

  async function addTask() {
    let newTask = { title: "" };
    tasks = [...tasks, newTask];

    await tick();
    newTask.input.focus();
  }
</script>

{#each tasks as task}
  <input type="text" bind:value={task.title} bind:this={task.input} />
{/each}

<button on:click={addTask}>Добавить задачу</button>

Преимущества последнего подхода

При использовании последнего метода, если массив tasks изначально не пуст, вы не столкнетесь с проблемами, связанными с прежним фокусом. Метод autofocus и use:action могут оставить фокус на последнем введенном поле, что не всегда является желаемым поведением. Однако, используя tick, вы можете явно контролировать, когда фокус должен перемещаться, что улучшает взаимодействие пользователя с интерфейсом.

Заключение

Каждый из перечисленных методов имеет свои преимущества и недостатки в зависимости от вашего конкретного случая использования. Рекомендуется выбирать тот подход, который наилучшим образом соответствует вашим требованиям по доступности и пользовательскому опыту.

Оцените материал
Добавить комментарий

Капча загружается...