我应该如何将 Svelte Reactivity 与 DOM getElementById 一起使用?

Ahm*_*etK 2 javascript scroll scrollbar svelte svelte-component

我有一个可滚动的 div 元素

    <script>
        let scrollBoxObj;
        $: scrollBoxObj = document.getElementById("chat-box");
        
        $: if (!(scrollBoxObj === undefined) && scrollBoxObj.scrollTop < scrollBoxObj.scrollHeight) {
            scrollBoxObj.scrollTop = scrollBoxObj.scrollHeight;
        }
    </script>
    <div id="scrollBox" class="h-screen w-auto chat-box border border-orange rounded">
        <div id="chat-box" style="margin: 0" class="chat-box">
            {#each chatBox as { user, content, type}}
                <MessageBox {user} message={content} {type} />
            {/each}
        </div>
    </div>

    <style>
        .chat-box {
            overflow-y: auto;
        }
    </style>
Run Code Online (Sandbox Code Playgroud)

我正在尝试在添加新消息时自动向下滚动。但它不是反应性的。或者我不明白反应性在苗条中是如何工作的。我也尝试在 onMount 中分配 scrollBoxObj 但它仍然是相同的结果不起作用。

Ste*_*aes 5

在 Svelte 中,$: x = y当方程左侧发生变化时(y部分)起作用。

在您的代码中,您有

$: scrollBoxObj = document.getElementById("chat-box");
Run Code Online (Sandbox Code Playgroud)

在左侧,我们有一个字符串(“chat-box”),它是一个永远不会改变的常量,还有一个永远不会改变的文档,这意味着反应性不会像你期望的那样工作。

当使用document.getElementById(或任何其他选择器方法)与 Svelte 一起工作时,被认为是不好的做法,因为您直接与 DOM 交互,而您的 DOM 应该反映您的状态。简而言之:不要这样做。

Svelte 为您提供了一种简单的方法来将 DOM 节点(如div)绑定到变量,只需添加bind:this={variable}

在你的情况下,这将变成:

<script>
 let scrollbox
</script>

<div bind:this={scrollbox}>
 ...
</div>
Run Code Online (Sandbox Code Playgroud)

反应的声明(中,如果里面的变化,这是滚动框你的情况块)将执行一旦有事情:

$: if (scrollBoxObj && scrollBoxObj.scrollTop < scrollBoxObj.scrollHeight) {
  scrollBoxObj.scrollTop = scrollBoxObj.scrollHeight;
}
Run Code Online (Sandbox Code Playgroud)

请再次注意,这只会在滚动框更改时触发,一旦绑定,您将不会重新触发(例如,当用户滚动时,它不会执行任何操作),因为您可能应该使用on:scroll事件。