You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Svelte中{#each}块添加新项后如何滚动到最后一项?

在Svelte中获取循环最后一项引用并实现自动滚动

问题场景

我通过以下代码在Svelte中渲染messages数组:

{#each messages as message, i}
    {@const isLast = i === messages.length - 1}
    
    <div class="card" class:active={isLast}>
        {message}
    </div>

{/each}

同时编写了追加数组元素的函数:

function addNextWord(){
    messages = [...messages, words[index]];
}

执行addNextWord后,需要将新添加的最后一项滚动到视图中(使用Element.scrollIntoView),但不知道如何获取循环中最后一项的DOM引用。

解决方法

方法1:条件绑定DOM引用

给循环中的最后一项单独绑定DOM引用,仅当元素是最后一项时赋值:

<script>
    import { tick } from 'svelte';
    let messages = [];
    let words = ['foo', 'bar', 'baz'];
    let index = 0;
    let lastCard;

    function addNextWord(){
        messages = [...messages, words[index]];
        index = (index + 1) % words.length;
        // 等待Svelte异步更新DOM后执行滚动
        tick().then(() => {
            lastCard?.scrollIntoView({ behavior: 'smooth' });
        });
    }
</script>

{#each messages as message, i}
    {@const isLast = i === messages.length - 1}
    
    <div 
        class="card" 
        class:active={isLast}
        bind:this={isLast ? lastCard : null}
    >
        {message}
    </div>
{/each}

<button on:click={addNextWord}>添加元素</button>

核心逻辑:通过bind:this={isLast ? lastCard : null}只给最后一项绑定引用,再用tick()等待DOM更新完成后调用滚动方法。

方法2:绑定所有项的引用数组

给循环中的每个元素绑定引用到数组,之后直接取数组最后一项:

<script>
    import { tick } from 'svelte';
    let messages = [];
    let words = ['foo', 'bar', 'baz'];
    let index = 0;
    let cardRefs = [];

    function addNextWord(){
        messages = [...messages, words[index]];
        index = (index + 1) % words.length;
        tick().then(() => {
            const lastRef = cardRefs.at(-1);
            lastRef?.scrollIntoView({ behavior: 'smooth' });
        });
    }
</script>

{#each messages as message, i (i)}
    <div 
        class="card" 
        class:active={i === messages.length - 1}
        bind:this={cardRefs[i]}
    >
        {message}
    </div>
{/each}

<button on:click={addNextWord}>添加元素</button>

这种方式会保存所有元素的引用,适合需要操作多个循环项的场景,注意要给each块加上键值(i)确保引用数组和元素对应。

方法3:利用生命周期钩子+选择器

如果已经给最后一项添加了active类,可以通过afterUpdate钩子自动检测并滚动:

<script>
    import { afterUpdate } from 'svelte';
    let messages = [];
    let words = ['foo', 'bar', 'baz'];
    let index = 0;

    function addNextWord(){
        messages = [...messages, words[index]];
        index = (index + 1) % words.length;
    }

    afterUpdate(() => {
        const lastCard = document.querySelector('.card.active');
        lastCard?.scrollIntoView({ behavior: 'smooth' });
    });
</script>

{#each messages as message, i}
    {@const isLast = i === messages.length - 1}
    
    <div class="card" class:active={isLast}>
        {message}
    </div>
{/each}

<button on:click={addNextWord}>添加元素</button>

这种方式不需要手动绑定引用,但依赖类选择器的唯一性,适合样式已经区分最后一项的场景。

内容的提问来源于stack exchange,提问作者KyleMit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 16:34:53