Home > Enterprise >  How to automatically scroll only inside <div> tag in Vue.js
How to automatically scroll only inside <div> tag in Vue.js

Time:07-21

I am creating frontend using vue 2.

There I have a chat inside tag and have done auto-scroll to the end of chat on updated().

Unfortunately, it scrolls not only inside chat box but also the whole page to this moment. How to override it? (show the whole code for you to recognise that it's impossible to have a ref on last message but not div - loaded_messages is an array from API and dialogs - from WebSocket)

<template>
          <div  >
            <div id="chat-messages"  style=" 
                border: 1px solid grey; overflow-y: scroll;">

                    <ol >

                  <div v-for="m in loaded_messages[0]"
                        direction="column"
                        justify-content="start"
                        align-items="end"
                        margin-left=2px
                        :key="m.id">
                   <li  v-if="m.username == user"> 
                    <b-avatar :src="m.get_message_info.get_thumbnail"></b-avatar>
                      <div >

                      <p>{{m.content}} </p>
                      <time>{{m.get_datetime}}</time>

                      </div>
                    </li>

                   <li  v-else> 
                    <b-avatar :src="m.get_message_info.get_thumbnail"></b-avatar>
                        <div >
                        <p>{{m.content}}</p>
                        <time>{{m.get_datetime}}</time>
                        </div>
                  </li>

                  </div>

                <div  v-for="dialog in dialogs"
                        direction="column"
                        justify-content="start"
                        align-items="end"
                        :key="dialog.id">

                   <li  v-if="dialog.username == user"> 
                    <b-avatar></b-avatar>
                      <div >
                              <p>{{dialog.message}} </p>
                              <time>{{dialog.datetime}}</time>
                      </div>
                    </li>

                   <li v-else> 
                    <b-avatar></b-avatar>
                    <div >
                            <p>  {{dialog.message}} </p>
                    </div>
                  </li>

                </div> 

                  <div ref="lastMessage"></div>
              </ol>
          </div>
        </div> 

</template>

<script>

        methods: { 

// scroll to the last message

      scrollToElement() {
      const [el] =  this.$refs.lastMessage;
      if (el) {
        el.scrollIntoView({ behavior: "smooth" });
      }
    },

   },

    updated() {
      this.scrollToElement();
    },

</script>

CodePudding user response:

scrollIntoView method doesn't support scrolling inside a container, it only works with the document viewport, you need to calculate the X distance to the top of the element.

You can use this method.

function scrollParentToChild(parent, child) {
// Where is the parent on page
  var parentRect = parent.getBoundingClientRect();
  // What can you see?
  var parentViewableArea = {
    height: parent.clientHeight,
    width: parent.clientWidth
  };

  // Where is the child
  var childRect = child.getBoundingClientRect();
  // Is the child viewable?
  var isViewable = (childRect.top >= parentRect.top) && (childRect.bottom <= parentRect.top   parentViewableArea.height);

  // if you can't see the child try to scroll parent
  if (!isViewable) {
        // Should we scroll using top or bottom? Find the smaller ABS adjustment
        const scrollTop = childRect.top - parentRect.top;
        const scrollBot = childRect.bottom - parentRect.bottom;
        if (Math.abs(scrollTop) < Math.abs(scrollBot)) {
            // we're near the top of the list
            parent.scrollTop  = scrollTop;
        } else {
            // we're near the bottom of the list
            parent.scrollTop  = scrollBot;
        }
  }

}
  • Related