使用Vue.js滚动到div底部

104

我有一个Vue.js组件,其中有几个元素。当组件中的某个方法被调用时,我希望自动滚动到该元素的底部。

基本上,与这里相同。 然而,我没有找到一种方法来获取我的组件内的元素并修改scrollTop

我目前正在使用Vue.js 2.0.8。


对我来说运行良好。 - yo yo
17个回答

135

2023平滑滚动功能,易于阅读,不会让你头疼...使用el.scrollIntoView()

scrollIntoView()有一些选项可以传递给它,比如scrollIntoView({behavior: 'smooth'}),可以获得开箱即用的平滑滚动效果,而且不需要任何外部库。

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

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

然后,如果你想在页面加载时滚动到这个元素,你可以像这样调用这个方法:
mounted() {
  this.scrollToElement();
}

如果你想在按钮点击或其他操作时滚动到它,你可以以同样的方式调用它:

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

滚动条在IE 8中完全可用。在IE或Safari中,平滑滚动效果不能直接使用。如果需要,在评论中@mostafaznv提到了此处的polyfill这里有一个fiddle示例

1
应该是<button @click="scrollToElement">滚动到我</button>而不是<button :click="scrollToElement">滚动到我</button>。记住,@是v-on的简写,:是v-bind的简写。 - Rohit Nair
1
这会将一个元素滚动到视图中,对我来说完美地工作。已点赞。 - James Shisiah
3
我必须使用更新的选项而不是挂载,但它完美地运作了 ;) - dippas
1
好的建议从不会伤害你的大脑。我搜索了两个多小时...谢谢,它非常好用。 - narasimharaosp
1
太好了。我能够在一个使用v-for循环生成的组件中添加mounted() {this.$el.scrollIntoView();},以便在添加新元素时自动滚动到该元素。 - Dustin Michels
显示剩余10条评论

119

据我理解,您想要的效果是在某些情况下(例如:向列表中添加项时),将列表(或可滚动的

)滚动到末尾。如果是这样,您可以仅使用纯JavaScript和VueJS选择器将容器元素(甚至是页面本身)滚动到末尾。

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

我在这个 fiddle中提供了一个可用的示例。

每次向列表添加项目时,列表将滚动到末尾以显示新项目。


39
你可以使用 ref 机制来选择你想要的 div,而不是使用 this.$el.querySelector - Existe Deja
3
如果没有解决方法,也许你应该搜索$nextTick()。在滚动之前,必须等待内容完全绘制。(请查看Alpesh的答案) - maugch
1
对于所有使用NUXT的人:您必须在页面上放置scrollToTop:false,以使其在更改路由之间生效。 - tObi
1
@GeorgeAbitbol Refs更多是一种最后的手段(hack),依赖它们可能会导致动态组件出现问题:例如,$refs对象不是响应式的,因此随着组件的添加和删除,它会继续增长。 - PeterT
这对我有用,但我确实使用了 this.$refs 来获取元素。 - Jesús Vera
显示剩余2条评论

41

我尝试了被接受的解决方案,但它对我没有用。我使用浏览器调试器,并发现实际应该使用的高度是 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;
},

这是一个不错的解决方案,但是任何与组件相关的操作都会触发更新钩子,并且在每次更新时元素将滚动到底部。 - schrodingercat
1
谢谢,我也遇到了同样的问题,采纳的答案没能解决,你的回答也解决了我的问题。 :) - Subtractive
1
更好的方法是将此放置在相关的观察器方法内,作为 $nextTick() 的回调函数(或等待它)。这将产生相同的效果,但可能需要更少的资源。 - phil294
2
对于使用NUXT的所有人:您必须在页面上放置scrollToTop: false,以便在更改路由时它能够正常工作。 - tObi

16
  1. 在DOM元素上使用ref属性进行引用
<div class="content scrollable" ref="msgContainer">
    <!-- content -->
</div>
  1. 你需要设置一个观察器(WATCH)
  data() {
    return {
      count: 5
    };
  },
  watch: {
    count: function() {
      this.$nextTick(function() {
        var container = this.$refs.msgContainer;
        container.scrollTop = container.scrollHeight + 120;
      });
    }
  }
  1. 确保您正在使用适当的CSS
.scrollable {
  overflow: hidden;
  overflow-y: scroll;
  height: calc(100vh - 20px);
}

1
非常有用的提示。我最初使用setTimeout解决了它,但这显然是正确的解决方案,以可靠地获得正确的时序。如果您不使用“nextTick”,则滚动可能会在渲染之前发生。 - Marian Klühspies
1
nextTick解决了我的问题。没有它就不行。谢谢Alpesh。 - LauroSkr
谢谢,这里大多数解决方案在点击时都可以正常工作,但使其在挂载时工作的唯一方法是使用“nextTick”。 - Moauya Meghari

9

这里是一个使用refdiv滚动到底部的简单示例。

/*
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>

注意,通过在HTML中添加ref='messageDisplay',您可以通过vueContent.$refs.messageDisplay访问该元素。


8

如果你需要支持IE11和(旧版)Edge浏览器,可以使用以下代码:

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

如果你不需要支持IE11,以下代码可以正常运行(更清晰的代码):
scrollToBottom() {
    let element = document.getElementById("yourID");
    element.scrollIntoView({behavior: "smooth", block: "end"});
}

5

尝试使用vue-chat-scroll

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

导入:

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

app.js 中,在 window.Vue = require('vue').default; 之后使用它,如下所示:
<ul class="messages" v-chat-scroll>
  // your message/chat code...
</ul>

4

如果以上没有找到可行的解决方案,我相信我有一个可行的解决方案。我的具体使用情况是,当数组中添加新消息时,我想要滚动到特定 div 的底部,例如我的聊天框。

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

在数据改变后滚动之前,我们需要等待dom更新,因此我必须使用nextTick!

我将上述代码放在了messages数组的watcher中:

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,
    }, 

观察器: { 数组名称: { handler() { const 容器 = this.$el.querySelector("#idName"); this.$nextTick(() => { 容器.scrollTop = 容器.scrollHeight; }); }, deep: true, }, },我发现这个方法很有用,谢谢。 - Saleheen Noor

3
在您发布的相关问题中,我们已经有一种使用纯JavaScript实现的方法,所以我们只需要获取我们想要滚动的dom节点的js引用。
可以使用{{link1:ref属性}}声明对html元素的引用,以便在vue的组件方法中使用它们。
或者,如果组件中的方法是某个UI事件的处理程序,并且目标与您想要在空间中滚动的div相关,则可以简单地{{link2:传递事件对象}}以及您想要的参数,并像scroll(event.target.nextSibling)这样进行滚动。

我发现这个选项似乎工作得很好,但是在设置滚动之后,在div中呈现字符串(我在同一个方法中更新字符串和滚动)。有没有办法在vue更新文本后更改滚动位置? - angrykoala
Vue.nextTick(function(){}) 等待下一次更新。 - Igor Skoric

3

这是对我有效的方法。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接