简体   繁体   English

使用 Vue.js 滚动到 div 的底部

[英]Scroll to bottom of div with Vue.js

I have a Vue.js component with several elements in it.我有一个 Vue.js 组件,其中包含多个元素。 I want to automatically scroll to the bottom of that element when a method in the component is called.当调用组件中的方法时,我想自动滚动到该元素的底部。

Basically, do the same as this .基本上,做同样的事情 However, I haven't found a way to get the element within my component and modify scrollTop但是,我还没有找到一种方法来获取组件中的元素并修改scrollTop

I'm currently using Vue.js 2.0.8.我目前正在使用 Vue.js 2.0.8。

2022 easy, readable, smooth scrolling ability, & won't hurt your brain... use el.scrollIntoView() 2022 简单、易读、流畅的滚动能力,而且不会伤害你的大脑……使用el.scrollIntoView()

scrollIntoView() has options you can pass it like scrollIntoView({behavior: 'smooth'}) to get smooth scrolling out of the box and does not require any external libraries. scrollIntoView()有一些选项,您可以像scrollIntoView({behavior: 'smooth'})一样传递它来获得开箱即用的平滑滚动,并且不需要任何外部库。

Here is a fiddle .这是一个小提琴

methods: {
  scrollToElement() {
    const el = this.$refs.scrollToMe;

    if (el) {
      // Use el.scrollIntoView() to instantly scroll to the element
      el.scrollIntoView({behavior: 'smooth'});
    }
  }
}

Then if you wanted to scroll to this element on page load you could call this method like this:然后,如果你想在页面加载时滚动到这个元素,你可以这样调用这个方法:

mounted() {
  this.scrollToElement();
}

Else if you wanted to scroll to it on a button click or some other action you could call it the same way:否则,如果您想通过单击按钮或其他操作滚动到它,您可以用相同的方式调用它:

<button @click="scrollToElement">scroll to me</button>

The scroll works all the way down to IE 8. The smooth scroll effect does not work out of the box in IE or Safari.滚动一直有效到 IE 8。平滑滚动效果在 IE 或 Safari 中无法开箱即用。 If needed there is a polyfill available for this here as @mostafaznv mentioned in the comments.如果需要,这里有一个可用的polyfill,正如评论中提到的@mostafaznv。

As I understand, the desired effect you want is to scroll to the end of a list (or scrollable div ) when something happens (eg: an item is added to the list).据我了解,您想要的效果是在发生某些事情时(例如:将项目添加到列表中)滚动到列表的末尾(或可滚动的div )。 If so, you can scroll to the end of a container element (or even the page it self) using only pure JavaScript and the VueJS selectors.如果是这样,您可以仅使用纯 JavaScript 和 VueJS 选择器滚动到容器元素的末尾(甚至是它本身的页面)。

var container = this.$el.querySelector("#container");
container.scrollTop = container.scrollHeight;

I've provided a working example in this fiddle .我在这个 fiddle中提供了一个工作示例。

Every time a item is added to the list, the list is scrolled to the end to show the new item.每次将项目添加到列表时,列表都会滚动到末尾以显示新项目。

Hope this helps you.希望这对您有所帮助。

I tried the accepted solution and it didn't work for me.我尝试了接受的解决方案,但它对我不起作用。 I use the browser debugger and found out the actual height that should be used is the clientHeight BUT you have to put this into the updated() hook for the whole solution to work.我使用浏览器调试器并发现应该使用的实际高度是clientHeight您必须将其放入updated()挂钩才能使整个解决方案正常工作。

data(){
return {
  conversation: [
    {
    }
  ]
 },
mounted(){
 EventBus.$on('msg-ctr--push-msg-in-conversation', textMsg => {
  this.conversation.push(textMsg)
  // Didn't work doing scroll here
 })
},
updated(){              <=== PUT IT HERE !!
  var elem = this.$el
  elem.scrollTop = elem.clientHeight;
},
  1. Use the ref attribute on the DOM element for reference使用 DOM 元素上的ref属性进行引用
<div class="content scrollable" ref="msgContainer">
    <!-- content -->
</div>
  1. You need to setup a WATCH您需要设置一个 WATCH
  data() {
    return {
      count: 5
    };
  },
  watch: {
    count: function() {
      this.$nextTick(function() {
        var container = this.$refs.msgContainer;
        container.scrollTop = container.scrollHeight + 120;
      });
    }
  }
  1. Ensure you're using proper CSS确保您使用正确的 CSS
.scrollable {
  overflow: hidden;
  overflow-y: scroll;
  height: calc(100vh - 20px);
}

Here is a simple example using ref to scroll to the bottom of a div .这是一个使用ref滚动到div底部的简单示例。

 /* Defined somewhere: var vueContent = new Vue({ el: '#vue-content', ... */ var messageDisplay = vueContent.$refs.messageDisplay; messageDisplay.scrollTop = messageDisplay.scrollHeight;
 <div id='vue-content'> <div ref='messageDisplay' id='messages'> <div v-for="message in messages"> {{ message }} </div> </div> </div>

Notice that by putting ref='messageDisplay' in the HTML, you have access to the element through vueContent.$refs.messageDisplay请注意,通过将ref='messageDisplay'放在 HTML 中,您可以通过vueContent.$refs.messageDisplay访问该元素

If you need to support IE11 and (old) Edge, you can use:如果需要支持 IE11 和(旧)Edge,可以使用:

scrollToBottom() {
    let element = document.getElementById("yourID");
    element.scrollIntoView(false);
}

If you don't need to support IE11, the following will work (clearer code):如果您不需要支持 IE11,以下将起作用(更清晰的代码):

scrollToBottom() {
    let element = document.getElementById("yourID");
    element.scrollIntoView({behavior: "smooth", block: "end"});
}

Try vue-chat-scroll :尝试vue-chat-scroll

Install via npm: npm install --save vue-chat-scroll通过 npm 安装: npm install --save vue-chat-scroll

Import:进口:

import Vue from 'vue'
import VueChatScroll from 'vue-chat-scroll'
Vue.use(VueChatScroll)

in app.js after window.Vue = require('vue').default;app.js之后window.Vue = require('vue').default;

then use it with :然后使用它:

<ul class="messages" v-chat-scroll>
  // your message/chat code...
</ul>

For those that haven't found a working solution above, I believe I have a working one.对于那些没有在上面找到可行解决方案的人,我相信我有一个可行的解决方案。 My specific use case was that I wanted to scroll to the bottom of a specific div - in my case a chatbox - whenever a new message was added to the array.我的具体用例是每当有新消息添加到数组时,我想滚动到特定 div 的底部——在我的例子中是一个聊天框。

const container = this.$el.querySelector('#messagesCardContent');
        this.$nextTick(() => {
          // DOM updated
          container.scrollTop = container.scrollHeight;
        });

I have to use nextTick as we need to wait for the dom to update from the data change before doing the scroll!我必须使用 nextTick 因为我们需要等待 dom 从数据更改中更新,然后再进行滚动!

I just put the above code in a watcher for the messages array, like so:我只是将上面的代码放在消息数组的观察器中,如下所示:

messages: {
      handler() {
        // this scrolls the messages to the bottom on loading data
        const container = this.$el.querySelector('#messagesCard');
        this.$nextTick(() => {
          // DOM updated
          container.scrollTop = container.scrollHeight;
        });
      },
      deep: true,
    }, 

In the related question you posted, we already have a way to achieve that in plain javascript, so we only need to get the js reference to the dom node we want to scroll.在您发布的相关问题中,我们已经有一种方法可以在纯 javascript 中实现这一点,因此我们只需要获取对要滚动的 dom 节点的 js 引用。

The ref attribute can be used to declare reference to html elements to make them available in vue's component methods. ref属性可用于声明对 html 元素的引用,以使它们在 vue 的组件方法中可用。

Or, if the method in the component is a handler for some UI event, and the target is related to the div you want to scroll in space, you can simply pass in the event object along with your wanted arguments, and do the scroll like scroll(event.target.nextSibling) .或者,如果method in the component是某个 UI 事件的处理程序,并且目标与您要在空间中滚动的 div 相关,您可以简单地将事件对象连同您想要的参数一起传递,然后像这样进行滚动scroll(event.target.nextSibling)

I had the same need in my app (with complex nested components structure) and I unfortunately did not succeed to make it work.我的应用程序有同样的需求(具有复杂的嵌套组件结构),但不幸的是我没有成功使它工作。

Finally I used vue-scrollto that works fine !最后我使用了vue-scrollto效果很好!

The solution did not work for me but the following code works for me.该解决方案对我不起作用,但以下代码对我有用。 I am working on dynamic items with class of message-box .我正在处理带有message-box类的动态项目。

scrollToEnd() {
            setTimeout(() => {
                this.$el
                    .getElementsByClassName("message-box")
                    [
                        this.$el.getElementsByClassName("message-box").length -
                            1
                    ].scrollIntoView();
            }, 50);
        }

Remember to put the method in mounted() not created() and add class message-box to the dynamic item.请记住将方法放在mounted()中而不是created()中,并将类message-box添加到动态项中。

setTimeout() is essential for this to work. setTimeout()对此工作至关重要。 You can refer to https://forum.vuejs.org/t/getelementsbyclassname-and-htmlcollection-within-a-watcher/26478 for more information about this.您可以参考https://forum.vuejs.org/t/getelementsbyclassname-and-htmlcollection-within-a-watcher/26478了解更多信息。

This is what worked for me这对我有用

this.$nextTick(() => {
   let scrollHeight = this.$refs.messages.scrollHeight
   window.scrollTo(0, scrollHeight)
})

My solutions without modules :没有模块的解决方案:

Template模板

<div class="scrollable-content" ref="conversations" />

Script脚本

scrollToBottom() {
  const container = this.$refs.conversations;
  container.scrollTop = container.scrollHeight;
},
scrollToBottom() {
    this.$nextTick(function () {
        let BoxEl = document.querySelector('#Box');
        if(BoxEl)
            BoxEl.scrollTop = BoxEl.scrollHeight;
    });
}

Agree with Lurein Perera同意卢雷恩·佩雷拉

Just want to add extra info只是想添加额外的信息

watch: {
    arrayName: {
      handler() {
        const container = this.$el.querySelector("#idName");
        this.$nextTick(() => {
          container.scrollTop = container.scrollHeight;
        });
      },
      deep: true,
    },
  },

Where as:然而:

arrayName = Name of array arrayName = 数组名称

idName = The id attribute has to be added to the div where you want the scrollbar to auto-scroll down when arrayName length increases. idName = id 属性必须添加到您希望滚动条在 arrayName 长度增加时自动向下滚动的 div 中。

  scrollToElement() {
    const element = this.$refs.abc; // here abc is the ref of the element

    if (element) {
      el.scrollIntoView({behavior: 'smooth'});
    }
  }
}

here you need to use ref for the particular div or element which you want make visible on scroll.在这里,您需要将 ref 用于要在滚动时显示的特定 div 或元素。

if you have a table and you want to locate the last row of the table then you have to use -如果你有一张桌子,并且你想找到桌子的最后一行,那么你必须使用 -

element.lastElementChild.scrollIntoView({behaviour:'smooth'})

Here not that if you ware asynchronously adding the element to the table then you have to take care of it.这并不是说如果您将元素异步添加到表中,那么您必须处理它。 you can test it using setTimeout, if that is making any difference.您可以使用 setTimeout 对其进行测试,如果这有什么不同的话。

eg例如

    const element = this.$refs.abc;
    if (element) {
      setTimeout(() => {
        element.lastElementChild.scrollIntoView({behaviour:'smooth'})
      }, 1000);

    }
  }

replace set timeout with your own async logic.用您自己的异步逻辑替换设置超时。

Using Composition API and TypeScript使用组合 API 和 TypeScript


I set the parameter scrollTop equal to scrollHeight from the HTMLDivElment API.我将参数scrollTop设置为scrollHeight API 中的HTMLDivElment

<template>
 <div id="container" ref="comments">
  Content ...
 </div>
</template>
<script lang="ts>
import { defineComponent, ref, Ref, watchEffect } from 'vue'

export default defineComponent({
 setup() {
  const comments: Ref<null | HTMLDivElement> = ref(null)

  watchEffect(() => {
   if(comments.value) {
    comments.value.scrollTop = comments.value.scrollHeight
   }
  })

  return {
   comments
  }
 }
})
</script>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM