The problem of scrolling faster and faster when messages scroll horizontally in Vue

Recently, when working on a project, two components need to be interacted. One poll gets the message and then passes it to another component for horizontal rolling display. As a result, the rolling speed is faster and faster. Here's a note to remind myself. The code for scrolling messages is at the bottom for easy use next time.

Background: Recently, there is a requirement for component A to obtain messages by polling. After component A gets new messages, it passes the messages in component A to another component B. When component B receives the messages, it lets the messages scroll and play on the page.

The framework of this project is VUE. When component A gets new messages, it triggers the central event bus, listens for events in component B, and adds them to an array. When the timer is not moving, it triggers the rolling function. The function of message scrolling is to extract the first item from the message array, then scroll the message using a timer, and clear the timer when the message scrolls to the edge.

Question: In the process of message scrolling, it should be able to scroll at a given speed at the beginning, but when the time gets longer, the problem of message scrolling speed will arise.

Reason: When this problem arises, my first thought is that setInterval has not been cleared, because when the timer is not cleared, calling the timer again will cause multiple timers to execute simultaneously. For example, the first time is a timer, and the second click is two timers, each time is + 2, so the speed is constantly increasing. Rise. I looked at the scroll function I set up, which clears the timer when the message scrolls to the edge, so there is no problem in the scroll function. I looked at the event listener of the central event bus again and found that the problem was here. Because when I judge whether a timer is destroyed, I directly judge whether it is a number or a null. Because when the timer starts to run, every time it returns an ID (number) instead of the original object, I receive a new message when a message starts to scroll, and then I make two timers. This problem arises when running at the same time.

Solution: When the message scrolls to the edge of the box to destroy the timer, assign it to null, then modify the event listener of the central event, change its condition of judging that there is no timer to null, and then call the message scrolling function to satisfy the condition.

Code scrolling horizontally:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <style>
            * {
                margin: 0;
                padding: 0;
            }
            #title {
                position: relative;
                width: 10%;
                margin: 30px auto;
                line-height: 30px;
                height: 30px;
                border: 1px solid red;
                overflow: hidden;
            }
            #content {
                position: absolute;
                left: 0;
                line-height: 30px;
                display: inline-block;
            }
        </style>
    </head>
    <body>
        <div id="title">
            <span id="content">123</span>
        </div>
        <script>
            var wrapEle = document.getElementById('title');
            let contentEle = document.getElementById('content');
            let arr = [
                {news: 'This is a piece of news.'}
            ];
            let timer = null;
            move(wrapEle, contentEle);
            function move(wrap, item) {
                clearInterval(timer);
                if (!arr.length) { return false;}
                item.innerHTML = arr[0].news;
                arr.splice( 0, 1 );
                let allWidth = getCurrentStyle(wrap, 'width');
                let itemWidth = getCurrentStyle(item, 'width');
                item.style.left = allWidth + 'px';
                let speed = 2;
                let time = 50;
                timer = setInterval( () => {
                    let itemPlace = getCurrentStyle(item, 'left');
                    if (itemPlace < -itemWidth) {
                        clearInterval(timer);
                    }
                    item.style.left = itemPlace - speed + 'px';
                }, time)
            }
    
            function getCurrentStyle (ele, attr) {
                return window.getComputedStyle ? parseInt(window.getComputedStyle(ele, null)[attr]) : parseInt(ele.currentStyle[attr] );
            }
                
        </script>
    </body>
    </html>

Keywords: Javascript Vue IE

Added by christophe on Thu, 22 Aug 2019 13:10:31 +0300