代码之家  ›  专栏  ›  技术社区  ›  joedoesnotknow

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

  •  1
  • joedoesnotknow  · 技术社区  · 7 年前

    我正在尝试使用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 回复  |  直到 7 年前
        1
  •  4
  •   Emile Bergeron Dhaval Rajpara    3 年前

    this.$el

    Vue实例正在管理的根DOM元素。

    这个$埃尔 这个 #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

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

    虽然Vue示例通常使用本机DOM API,但使用 参考 在这种情况下更容易。