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

时间:2018-04-05 21:16:06

标签: javascript scroll vue.js vue-component

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

目前,我希望在发送新邮件时使带有邮件的容器自动滚动到底部。我尝试使用scrollToEnd函数选择div容器并将其scrollHeight分配给scrollTop

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>

1 个答案:

答案 0 :(得分:1)

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会更容易。