Frontend Development 5 min read

Vue Directive for Continuous List Scrolling Animation with Pause on Interaction

This article explains how to create a reusable Vue directive that animates a list scrolling continuously using requestAnimationFrame, allows pausing on mouse click, and lets users adjust the scroll speed, with a complete code example and detailed implementation notes.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Vue Directive for Continuous List Scrolling Animation with Pause on Interaction

Background and Requirements In large-screen projects, many lists often need continuous scrolling animations, leading to duplicated and hard‑to‑maintain code when speed or other parameters must be changed. The required features are: continuous up‑and‑down scrolling, pause on mouse click, resume on mouse leave, and adjustable scroll speed.

Demo An animated GIF demonstrates the scrolling effect, and the full implementation can be viewed at https://code.juejin.cn/pen/7400691681794162728 .

Explanation

Uses requestAnimationFrame to drive the animation and the timeStamp callback to control speed.

Encapsulated in a Vue directive; the mounted hook defines a variable isUsing to track whether the user is interacting (click, wheel, mouseenter/leave) and adds event listeners to pause or resume the animation accordingly.

Some Thoughts requestAnimationFrame is preferred over setTimeout or setInterval for data‑visualization animations because it synchronizes with the browser’s refresh cycle, offering better stability, interactivity, smoothness, and ease of use, and enjoys broad browser support. Fallbacks to setTimeout / setInterval can be added for legacy browsers.

Core Code

{
    arr: {},
    mounted(el, binding = { value: 200 }, vnode, prevVnode) {
        const gap = 1000 / 45; // frame gap, approx 60fps => 1000/60
        if (window.requestAnimationFrame) {
            let isUsing = false;
            // mouse leave – resume animation
            el.addEventListener('mouseleave', () => {
                isUsing && scrollAnimation();
                isUsing = false;
            }, { passive: true });
            // wheel – pause animation
            el.addEventListener('wheel', () => { isUsing = true; }, { passive: true });
            // click – pause animation
            el.addEventListener('click', () => { isUsing = true; }, { passive: true });
            const scrollAnimation = () => {
                if (window.requestAnimationFrame) {
                    const animationFun = (timeStamp, preTimeStamp = 0, diff = 0) => {
                        if (isUsing) return;
                        const currentDiff = preTimeStamp === 0 ? 0 : timeStamp - preTimeStamp;
                        const n_diff = currentDiff + diff;
                        if (n_diff < gap) {
                            window.requestAnimationFrame((_timeStamp) => animationFun(_timeStamp, timeStamp, n_diff));
                            return;
                        }
                        const scrollTop = el.scrollTop;
                        const clientHeight = el.clientHeight;
                        const scrollHeight = el.scrollHeight;
                        if (scrollTop + clientHeight < scrollHeight) {
                            el.scrollTop = scrollTop + 1;
                            window.requestAnimationFrame((_timeStamp) => animationFun(_timeStamp, timeStamp, 0));
                        } else {
                            el.scrollTop = 0;
                            scrollAnimation();
                        }
                    };
                    window.requestAnimationFrame(animationFun);
                }
            };
            scrollAnimation();
        } else {
            // fallback implementation
        }
    },
    unmounted(el, binding, vnode, prevVnode) {
        // cleanup if needed
    }
}

Additional Extensions The directive can accept extra parameters to manually control whether the list scrolls, and the scrolling animation can be replaced with other effects such as color changes, shape transformations, or displacement while keeping the same overall approach.

frontendanimationVuescrollingrequestAnimationFrameDirective
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.