skip to Main Content

I am trying to watch a computed value that gets filled up with messages from a store. This is it (code reduced for brevity):

<div ref="RefWindow">
 <ul v-for="Message in Feed">
   <li>Message</li>
  </ul>
</div>


const Feed = computed(() => MyStore.Messages)
const RefWindow = ref();

function scrollToBottom() {
      console.log(`scrollTop: ${RefWindow.value.scrollTop}, scrollHeight: ${RefWindow.value.scrollHeight}`)
      RefWindow.value.scrollTop = RefWindow.value.scrollHeight; // Scrolls to bottom
    }

 watch(() => Feed, async () => {
      await nextTick();
    
      scrollToBottom(); // Doesn't work console.log shows scrollTop: 0, scrollHeight: 0
 
      setTimeout(()=> scrollToBottom(), 20); // Works console.log shows scrollTop: 0, scrollHeight: 4203
      }
    }, {
      immediate: true,
      deep: true
    })

It was my understanding that nextTick() is almost like onUpdated lifecycle hook in that once Feed‘s value has changed, on the next update of the DOM the code should run. However without the setTimeout in place it seems the scrollHeight of the div RefWindow is not being updated.

What is the correct way to go about this without using a timeout?

2

Answers


  1. It’s not clear what happens since you didn’t provide your full template and better MRE.

    You could try flush: 'post' option for the watch:
    https://vuejs.org/guide/essentials/watchers#post-watchers

    Login or Signup to reply.
  2. Just use a directive:

    Playground

    <script setup>
    import {ref} from 'vue';
    setTimeout(() => {
      Feed.value = Array.from({length: 100});
    }, 1000)
    const Feed = ref([]);
    const RefWindow = ref();
    
    const vScroll = (el, {value}) => {
      if(!value) return;
      console.log(`scrollTop: ${RefWindow.value.scrollTop}, scrollHeight: ${RefWindow.value.scrollHeight}`)
      RefWindow.value.scrollTop = RefWindow.value.scrollHeight; // Scrolls to bottom
    };
    </script>
    <template>
      <div ref="RefWindow" style="height: 500px; border: 1px solid gray;padding: 10px; overflow: auto">
     <ul v-for="(Message, idx) in Feed">
       <li v-scroll="idx===Feed.length -1">Message</li>
      </ul>
    </div>
    </template>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search