frontend: improve channel switch latency by reducing reflows due to scroll-related getters
This commit is contained in:
parent
15e57c2372
commit
9122434a36
2 changed files with 39 additions and 31 deletions
28
frontend/src/components/pages/main/Message.svelte
Normal file
28
frontend/src/components/pages/main/Message.svelte
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<script>
|
||||||
|
export let message;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.message {
|
||||||
|
overflow-x: none;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-content {
|
||||||
|
color: var(--foreground-color-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pending {
|
||||||
|
color: var(--foreground-color-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.author {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-right: var(--space-xxs);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="message">
|
||||||
|
<span class="author">{ message.author_username }</span>
|
||||||
|
<span class="message-content" class:pending={ message._isPending }>{ message.content }</span>
|
||||||
|
</div>
|
|
@ -1,27 +1,25 @@
|
||||||
<script>
|
<script>
|
||||||
import { afterUpdate, beforeUpdate } from "svelte";
|
import { afterUpdate, beforeUpdate, onMount } from "svelte";
|
||||||
import { messagesStoreProvider } from "../../../stores.js";
|
import { messagesStoreProvider } from "../../../stores.js";
|
||||||
|
import Message from "./Message.svelte";
|
||||||
|
|
||||||
export let channelId;
|
export let channelId;
|
||||||
let scrollTarget;
|
let scrollTarget;
|
||||||
let shouldAutoscroll = false;
|
let scrollAnchor;
|
||||||
|
let shouldAutoscroll = true;
|
||||||
let lastScrollHeight = null;
|
let lastScrollHeight = null;
|
||||||
|
|
||||||
$: messages = messagesStoreProvider.getStore(channelId);
|
$: messages = messagesStoreProvider.getStore(channelId);
|
||||||
|
|
||||||
beforeUpdate(() => {
|
|
||||||
shouldAutoscroll = scrollTarget && (scrollTarget.offsetHeight + scrollTarget.scrollTop) > (scrollTarget.scrollHeight - 20);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterUpdate(() => {
|
afterUpdate(() => {
|
||||||
// hacky way to preserve scroll position when messages are pushed back
|
// hacky way to preserve scroll position when messages are pushed back
|
||||||
if (lastScrollHeight) {
|
if (lastScrollHeight) {
|
||||||
scrollTarget.scrollTop = scrollTarget.scrollHeight - lastScrollHeight;
|
scrollTarget.scrollTop = scrollTarget.scrollHeight - lastScrollHeight;
|
||||||
lastScrollHeight = null;
|
lastScrollHeight = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (shouldAutoscroll && scrollTarget) {
|
if (shouldAutoscroll && scrollAnchor) {
|
||||||
scrollTarget.scrollTo(0, scrollTarget.scrollHeight);
|
scrollAnchor.scrollIntoView(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -29,7 +27,9 @@
|
||||||
const { scrollTop, offsetHeight, scrollHeight } = e.target;
|
const { scrollTop, offsetHeight, scrollHeight } = e.target;
|
||||||
if ((scrollTop + offsetHeight) >= scrollHeight) { // user scrolled to bottom
|
if ((scrollTop + offsetHeight) >= scrollHeight) { // user scrolled to bottom
|
||||||
messages.setIsCollectingOldMessages(true);
|
messages.setIsCollectingOldMessages(true);
|
||||||
|
shouldAutoscroll = true;
|
||||||
} else {
|
} else {
|
||||||
|
shouldAutoscroll = false;
|
||||||
if (scrollTop === 0) {
|
if (scrollTop === 0) {
|
||||||
// load older messages if the user scrolls to the top.
|
// load older messages if the user scrolls to the top.
|
||||||
// save the current scroll height if the server returned any messages,
|
// save the current scroll height if the server returned any messages,
|
||||||
|
@ -57,31 +57,11 @@
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
background-color: var(--background-color-1);
|
background-color: var(--background-color-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.message {
|
|
||||||
overflow-x: none;
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-content {
|
|
||||||
color: var(--foreground-color-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.pending {
|
|
||||||
color: var(--foreground-color-3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.author {
|
|
||||||
font-weight: bold;
|
|
||||||
margin-right: var(--space-xxs);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="messages-container" on:scroll={ onScroll } bind:this={ scrollTarget }>
|
<div class="messages-container" on:scroll={ onScroll } bind:this={ scrollTarget }>
|
||||||
{#each $messages as message (message.id)}
|
{#each $messages as message (message.id)}
|
||||||
<div class="message">
|
<Message message={message} />
|
||||||
<span class="author">{ message.author_username }</span>
|
|
||||||
<span class="message-content" class:pending={ message._isPending }>{ message.content }</span>
|
|
||||||
</div>
|
|
||||||
{/each}
|
{/each}
|
||||||
|
<div bind:this={ scrollAnchor } />
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue