繁体   English   中英

添加新元素时如何滚动到div的底部

[英]How to scroll to bottom of div when new elements are added

我正在尝试使用 Vue 和 Express 制作聊天应用程序。

目前,我想让带有消息的容器在发送新消息时自动滚动到底部。 我尝试通过使用选择 div 容器并将其scrollHeight分配给scrollTopscrollToEnd函数来做到这一点:

scrollToEnd: function () {
    var messages = this.$el.querySelector('#messages')
    messages.scrollTop = messages.scrollHeight
}

这给出了以下错误:

TypeError:无法读取 null 的属性“scrollHeight”

出于某种原因,使用querySelector总是返回 null,当我在其他元素上测试它时也是如此。

可以在下面找到该组件的完整代码。

<template>
    <div id="messages">
        <ul>
            <li v-for="msg in messages.slice().reverse()">{{ msg.message }}</li>
        </ul>
    </div>
</template>

<script>
import MessageService from '@/services/MessageService'

export default {
    name: 'messages',
    data () {
        return {
            messages: []
        }
    },
    mounted () {
        this.getMessages()

        this.$root.$on('newMessage', (msg) => {
            this.message = msg
            this.getMessages()
            this.scrollToEnd()
        })
    },
    methods: {
        async getMessages () {
            const response = await MessageService.fetchMessages()
            this.messages = response.data.messages
        },
        scrollToEnd: function () {
            var messages = this.$el.querySelector('#messages')
            messages.scrollTop = messages.scrollHeight
        }
    }
}
</script>

this.$el

Vue 实例管理的根 DOM 元素。

this.$el#messages div,无需从DOM 中获取它。

然后,您可以使用this.$el.lastElementChild.offsetTop来获取最后一条消息并滚动到它的顶部,所以如果它很长,您就不会滚动超过它的起点。

在这里,我稍微简化了模板以使其直截了当。

<template>
    <ul id="messages">
        <li v-for="msg in messages.slice().reverse()">{{ msg.message }}</li>
    </ul>
</template>

<script>
export default {
    name: 'messages',
    data() {
        return { messages: [] };
    },
    mounted() {
        this.getMessages();
    },
    updated() {
        // whenever data changes and the component re-renders, this is called.
        this.$nextTick(() => this.scrollToEnd());
    },
    methods: {
        async getMessages () {
            // ...snip...
        },
        scrollToEnd: function () {
            // scroll to the start of the last message
            this.$el.scrollTop = this.$el.lastElementChild.offsetTop;
        }
    }
}
</script>

如果你真的想保留<div>容器,你可以使用ref

<template>
    <div id="messages">
        <ul ref="list">
            <li v-for="msg in messages.slice().reverse()">{{ msg.message }}</li>
        </ul>
    </div>
</template>

然后在组件中,你可以通过this.$refs.list来引用它。

ref用于注册对元素或子组件的引用。 该引用将注册在父组件的$refs对象下。 如果在普通 DOM 元素上使用,则引用将是该元素; 如果在子组件上使用,引用将是组件实例。

虽然 Vue 示例经常使用原生 DOM API 来解决问题,但在这种情况下使用ref更容易。

暂无
暂无

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

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