Skip to content
Advertisement

Vue.js render previous chat messages without changing the postition of current messages on screen

I use v-for to render the message list. when the first batch of messages are rendered, I use scrollIntoView() on the newest one so the container scrolls to bottom. as the user scrolls up I fetch previous messages to create a seamless scroll. the problem is that when new messages are rendered, the scroll goes to the top of the container.

I tried saving the first message id in the list before updating the list with fetched messages and then scrolling back to that message but it causes a jump on the screen for a moment and is not a good user experience.

how can I prepend and render older messages to the message list so that current messages stay in their place wherever they are on the screen?

message list is stores in vuex and I update it using this action:

HandleMessageList({state, commit}, msgList) {
    const currentMessages = state.messages
    const updatedMessages = msgList.concat(currentMessages)
    commit('SET_MESSAGES', updatedMessages)
}

and in template:

<template>
  <div class=msg-container" ref="messageDisplayArea">
    <message-object
      v-for="msg in msgList"
      :key="msg.id"
    />
  </div>
</template>

<script>
import {mapState} from "vuex";

export default {
  name: "MessageDisplay",
  components: {
    MessageObject,
  },
  computed: {
    ...mapState({
      msgList: state => state.messages,
    }),
  },
  updated() {
    this.$nextTick(() => this.scrollToTarget())
  },
  mounted() {
    this.$refs.messageDisplayArea.addEventListener('scroll', this.handleUserScroll)
  },
  beforeDestroy() {
    this.$refs.messageDisplayArea.removeEventListener('scroll', this.handleUserScroll)
  },
  methods: {
    scrollToTarget() {
       // ... scroll back to the position before message list update
    },
    handleUserScroll(e) {
      const scrollTop = e.target.scrollTop
      const scrollHeight = e.target.scrollHeight
      const elementHeight = e.target.offsetHeight
      if (scrollTop === 0 && elementHeight < scrollHeight) {
        // ... fetch older messages
      }
    },
  },
}
</script>

versions:

vue 2.6.10
vuex 3.0.1

Advertisement

Answer

I found the behavior I wanted in this Quasar component

it is an infinite scroll component but the main part is that the scroll can be in reverse which is necessary for a chat message scroll.

Advertisement