如何在Svelte中专注于新添加的输入?

32

我使用 #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}>Add task</button>
3个回答

45

Rich Harris提供了更好的解决方案


你可以使用use:action

当元素被创建时,会调用函数。

例如:
<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}>Add task</button>

2
@AntonZotov 不出所料,Rich Harris 有一个更好的解决方案。 - CD..
2
你的也很好。我之所以使用它,是因为在使用自动对焦时遇到了一些问题。虽然我没有深入研究,但这可能与Chrome 79中的一个缺陷有关:当URL包含片段时,自动对焦无法正常工作:https://bugs.chromium.org/p/chromium/issues/detail?id=1046357 - voscausa
现在不推荐使用“autofocus”;Svelte语言工具也不鼓励使用它。使用属性绝对是更优雅的解决方案,而且没有警告! - Jordan Mann
2
据我所知,这个解决方案对于a11y来说并没有比Rich Harris的解决方案更好。它只是绕过了Svelte的警告。它在愚弄Svelte,但不应该愚弄我们! - pglezen
这是一个很棒的解决方案,因为它非常灵活。 - khaki

43

你可以使用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}>Add task</button>
请注意,您将收到无障碍警告。这是因为辅助功能指南实际上建议您不要这样做:
“盲人或视力低下者在没有得到许可的情况下移动焦点时可能会感到迷失方向。此外,自动对焦对于运动控制障碍的人来说可能会带来问题,因为它可能会为他们创建额外的工作,以从自动对焦区域导航到页面/视图的其他位置。”
由您决定是否在您的情况下应用此建议!

两个提出的答案都不适用于我的情况;我来解释一下:我有一个带有2个输入框的表单,在提交表单后,我想让光标回到第一个输入框。有什么建议吗?谢谢! - Ad Rienks
4
使用 <input bind:this={myInput}> 获取要聚焦的输入框的引用,然后在表单提交后调用 myInput.focus() - Rich Harris
谢谢,这是一个很好的解决方案!但是,我想要更多:不仅在提交之后,还要在提交之前。注意:解决方案是使用自动对焦! - Ad Rienks
1
如果在页面加载阶段自动聚焦到“用户名”输入框,您是否仍然认为这是可访问性问题?例如:用户单击“登录”链接,该链接将其重定向到登录页面,登录页面加载完成后,“用户名”输入框会自动获得焦点。当您处于单个应用程序模式时,是否有所不同? - Tal

17

你可以使用 bind:thistick

例如:

<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}>Add task</button>

我方法的优势说明

如果tasks数组最初不为空会发生什么? 那么autofocususe:action方法的缺点在于,当列表最初显示时,焦点在最后一个字段上。这可能是不可取的。

我的方法只在单击添加按钮时控制焦点。


3
Tick是我在应用程序中所需的元素,因为它之前被隐藏在一个{#if}后面,所以它还不存在。 - David Parker
input 是从哪里来的?它不是 task 的属性。 - Dennis
@Dennis task.input 属性是通过循环中每个输入元素上的 bind:this={task.input} 指令设置的。 - magnusdahlstrand
@Dennis task.input属性是通过循环中每个输入元素上的bind:this={task.input}指令设置的。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接