admin管理员组

文章数量:1335371

Learning Vue. Trying to get a chat window div to scroll to the top when a new chat entry is found.

My Vue ponent is:

const app = new Vue({ 
    el: '#toolbar-chat',

    data: {
        messages: []
    },

    created() {
        this.fetchMessages();

        Echo.private(chat_channel)
            .listen('ChatMessageSent', (e) => {
                this.messages.unshift({
                    message: e.data.message,
                    player: e.data.player.nickname
                });
            });
    },

    methods: {
        fetchMessages() {
            axios.get(chat_get_route)
                .then(response => {
                    this.messages = response.data;
                });
        },

        addMessage(message) {
            this.messages.unshift(message);

            this.$nextTick(() => {
                this.$refs.msgContainer.scrollTop = 0;
            });

            axios.post(chat_send_route, message)
                .then(response => {
                    console.log(response.data);
                });

        }
    }
});

My chat message Template

<template>
    <div ref="msgContainer" class="toolbar-chat">
        <div class="row">
            <div class="col-xs-12" v-for="message in messages">
                <strong class="primary-font">
                    {{ message.player.nickname }}:
                </strong>
                {{ message.message }}
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        props: ['messages']
    };
</script>

My chat send template

<template>
    <div class="input-group input-group-sm">
        <input id="btn-input" type="text" class="form-control" value="" required="required"  maxlength="140" placeholder="Type your message here..." v-model="newMessage" @keyup.enter="sendMessage">
        <div class="input-group-btn">
            <button class="btn btn-primary" type="button"  id="btn-chat" @click="sendMessage">
                <i class="fa fa-paper-plane"></i>
            </button>
        </div>
    </div>
</template>

<script>
    export default {
        props: ['player'],

        data() {
            return {
                newMessage: ''
            }
        },

        methods: {
            sendMessage() {
                this.$emit('chatmessagesent', {
                    player: this.player,
                    message: this.newMessage
                });

                this.newMessage = ''
            }
        }
    }
</script>

And in my page I include the templates

<div class="col-xs-12 col-md-4" id="toolbar-chat">
    <chat-messages :messages="messages"></chat-messages>
    <chat-form v-on:chatmessagesent="addMessage" :player="{{ Auth::user() }}"></chat-form>
</div>

A message adds to the list OK, but I get this error:

[Vue warn]: Error in nextTick: "TypeError: Cannot set property 'scrollTop' of undefined"

Is it the way the element is named (camelCase)? What have I missed.

Learning Vue. Trying to get a chat window div to scroll to the top when a new chat entry is found.

My Vue ponent is:

const app = new Vue({ 
    el: '#toolbar-chat',

    data: {
        messages: []
    },

    created() {
        this.fetchMessages();

        Echo.private(chat_channel)
            .listen('ChatMessageSent', (e) => {
                this.messages.unshift({
                    message: e.data.message,
                    player: e.data.player.nickname
                });
            });
    },

    methods: {
        fetchMessages() {
            axios.get(chat_get_route)
                .then(response => {
                    this.messages = response.data;
                });
        },

        addMessage(message) {
            this.messages.unshift(message);

            this.$nextTick(() => {
                this.$refs.msgContainer.scrollTop = 0;
            });

            axios.post(chat_send_route, message)
                .then(response => {
                    console.log(response.data);
                });

        }
    }
});

My chat message Template

<template>
    <div ref="msgContainer" class="toolbar-chat">
        <div class="row">
            <div class="col-xs-12" v-for="message in messages">
                <strong class="primary-font">
                    {{ message.player.nickname }}:
                </strong>
                {{ message.message }}
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        props: ['messages']
    };
</script>

My chat send template

<template>
    <div class="input-group input-group-sm">
        <input id="btn-input" type="text" class="form-control" value="" required="required"  maxlength="140" placeholder="Type your message here..." v-model="newMessage" @keyup.enter="sendMessage">
        <div class="input-group-btn">
            <button class="btn btn-primary" type="button"  id="btn-chat" @click="sendMessage">
                <i class="fa fa-paper-plane"></i>
            </button>
        </div>
    </div>
</template>

<script>
    export default {
        props: ['player'],

        data() {
            return {
                newMessage: ''
            }
        },

        methods: {
            sendMessage() {
                this.$emit('chatmessagesent', {
                    player: this.player,
                    message: this.newMessage
                });

                this.newMessage = ''
            }
        }
    }
</script>

And in my page I include the templates

<div class="col-xs-12 col-md-4" id="toolbar-chat">
    <chat-messages :messages="messages"></chat-messages>
    <chat-form v-on:chatmessagesent="addMessage" :player="{{ Auth::user() }}"></chat-form>
</div>

A message adds to the list OK, but I get this error:

[Vue warn]: Error in nextTick: "TypeError: Cannot set property 'scrollTop' of undefined"

Is it the way the element is named (camelCase)? What have I missed.

Share Improve this question edited Sep 2, 2018 at 23:56 Phil 165k25 gold badges262 silver badges267 bronze badges asked Aug 17, 2017 at 0:03 TheRealPapaTheRealPapa 4,5399 gold badges80 silver badges165 bronze badges 4
  • What does the template look like? $refs only refers to child elements with a ref attribute. If you want the root element (ie #toolbar-chat), use this.$el – Phil Commented Aug 17, 2017 at 0:06
  • Hi @Phil, thanks for the response. I updated my Q with all the pieces. I will look at your suggestion – TheRealPapa Commented Aug 17, 2017 at 0:11
  • So which div is it you want to scroll? – Phil Commented Aug 17, 2017 at 0:24
  • Sorry @Phil, based on your reply before I updated above. I added a ref="msgContainer" and call it in $nextTick. – TheRealPapa Commented Aug 17, 2017 at 0:26
Add a ment  | 

2 Answers 2

Reset to default 3

Since the element you want to scroll is within a ponent, you should implement a method on that ponent that you can call.

For example, in your chat-messages ponent...

methods: {
  scrollToTop () {
    this.$el.scrollTop = 0
  }
}

and in your Vue instance, add a ref for that ponent...

<chat-messages ref="messages"...

and in the addMessage method...

this.$refs.messages.scrollToTop()

We can use scrollIntoView() method for such purpose, e.g:

this.$refs.yourRef.$el.scrollIntoView();

本文标签: javascriptVue scroll div to top inside methodStack Overflow