I'm trying to make a chat window, where when I send/get a message, the window scrolls to the very bottom. That's how I make it:
template:
<ul class="chat-window">
<li v-for="message in messages">
<span>{{ message.from }}</span>{{ message.message }}
</li>
</ul>
script:
const messages = ref()
socket.on('chat-message', (data) => {
messages.value.push(data)
const chatWindow = document.querySelector('.chat-window')
chatWindow.scrollTop = chatWindow.scrollHeight
})
But when coded this way, the last message is never seen (you need to scroll to it).
I found out that when I use setTimeout, like this:
setTimeout(() => {
const chatWindow = document.querySelector('.chat-window')
chatWindow.scrollTop = chatWindow.offsetHeight
}, 10)
then it works fine. So I know how to make it work, but I don't know why I need to use setTimeout. Can anybody please explain? Is there a better way to do it?
The reason why it works with
setTimeoutis the lifecycle of a vue component. You should read the documentation page to understand the how the lifecycle works.So if you set a variable like you do
Vue needs to run a new lifecycle to update the component. If you access the DOM directly after the change of the value, Vue might not have been updated the component yet.
But, you can actively say, you want to wait for the update to be done with the
nextTickfunction: https://vuejs.org/api/general.html#nexttickInstead of using querySelector you should use a template ref for the html element as described here: https://vuejs.org/guide/essentials/template-refs.html