Implementing Entry Animations and Seamless Scrolling in a Vue 3 Big‑Screen Visualization Project
This article demonstrates how to add entry animations and implement seamless horizontal and vertical scrolling in a Vue 3‑based big‑screen visualization project using ECharts, Gaode map, Pinia, CSS keyframes, and the animejs library, with complete code examples and component packaging.
This tutorial describes a big‑screen visualization project built with Vue 3, ECharts, Gaode map, and Pinia, providing features such as screen adaptation, chart component encapsulation, map component encapsulation, drag‑drop layout, entry animations, and seamless scrolling.
Screen adaptation
Chart component (ECharts) encapsulation
Gaode map component encapsulation
Drag‑drop layout
Entry animations
Seamless scrolling
Source code: https://github.com/vangleer/es-big-screen
Online demo: https://vangleer.github.io/es-big-screen/#/screen
Preface
The previous article covered screen adaptation, chart component encapsulation, drag‑drop layout, and map component encapsulation. This post focuses on implementing entry animations and seamless scrolling.
Entry Animations
Final effect demonstration (image omitted)
Header Animation
File: src/views/screen/components/Header.vue – a simple fade‑in animation.
.es-screen-header {
animation: fade 3s;
}
@keyframes fade {
from { opacity: 0; }
to { opacity: 1; }
}Left Side Animation
File: src/views/screen/components/left/index.vue
.es-screen-left-item {
/* ... */
&:nth-child(1) { height: 550px; animation-duration: .8s; }
&:nth-child(2) { animation-duration: 1.5s; }
}
@keyframes slide {
0% { transform: translateX(-100%); }
80% { transform: translateX(20px); }
100% { transform: translateX(0); }
}The left side defines a slide‑in animation that starts from -100% and bounces to the final position.
Right Side Animation
File: src/views/screen/components/right/index.vue
.es-screen-right-item {
/* ... */
animation-name: slide;
&:nth-child(1) { animation-duration: 0.5s; }
&:nth-child(2) { animation-duration: 1s; }
&:nth-child(3) { animation-duration: 1.5s; }
}
@keyframes slide {
0% { transform: translateX(100%); }
80% { transform: translateX(-20px); }
100% { transform: translateX(0); }
}The right side uses the same keyframes but moves in the opposite direction.
Center Map Entry Animation
File: src/views/screen/components/center/index.vue
.es-center {
animation: slideAndFade 1.5s;
}
@keyframes slideAndFade {
0% { transform: translateY(218px); opacity: 0; }
100% { transform: translateX(0); opacity: 1; }
}The map slides up from the bottom while fading in.
Seamless Scrolling Component
Seamless scrolling is common in big‑screen dashboards. The following custom hook uses animejs to create a reusable horizontal/vertical scrolling solution.
Install the dependency:
yarn add animejsHook implementation ( useSeamlessScroll ) – full code kept intact:
import { onMounted, shallowRef, Ref } from 'vue'
import anime from 'animejs/lib/anime.es.js'
export type OptionsType = {
direction?: 'horizontal' | 'vertical'
gap?: number
duration?: number
}
export function useSeamlessScroll(listRef: Ref
, options: OptionsType = {}) {
const { direction = 'horizontal', gap = 10, duration = 10000 } = options
const animation = shallowRef
>(null)
function init() {
const isHorizontal = direction === 'horizontal'
const translateKey = isHorizontal ? 'translateX' : 'translateY'
const transKey = isHorizontal ? 'x' : 'y'
const children = listRef.value?.children || []
if (!children.length) return
const firstEl = children[0] as HTMLElement
const firstDiff = (isHorizontal ? firstEl.offsetWidth : firstEl.offsetHeight) + gap
listRef.value!.style.transform = `${translateKey}(-${firstDiff}px)`
const transList: any[] = []
let total = 0
anime.set(children, {
[translateKey]: (el: HTMLElement, i) => {
const distance = (isHorizontal ? el.offsetWidth : el.offsetHeight) + gap
total += distance
transList[i] = { [transKey]: total - distance }
}
})
listRef.value!.style[isHorizontal ? 'width' : 'height'] = total + 'px'
animation.value = anime({
targets: transList,
duration,
easing: 'linear',
direction: isHorizontal ? undefined : 'reverse',
[transKey]: `+=${total}`,
loop: true,
update: () => {
anime.set(children, {
[translateKey]: (el, i) => transList[i][transKey] % total
})
}
})
}
function pause() { animation.value!.pause() }
function play() { animation.value!.play() }
onMounted(() => { init() })
return { listRef, pause, play, animation }
}The hook accepts a listRef (a Vue Ref pointing to the scrolling container) and an optional options object to configure direction, gap, and duration.
Using the Hook
<template>
<div class="es-center-bottom">
<div ref="listRef" class="es-bottom-list">
<div v-for="item in 10" class="es-bottom-item">{{ item }}</div>
</div>
</div>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
import { useSeamlessScroll } from '@/utils/useSeamlessScroll'
const listRef = ref()
useSeamlessScroll(listRef)
</script>
<style scoped lang='scss'>
.es-center-bottom { position: relative; width: 100%; overflow: hidden; height: 150px; }
.es-bottom-item { position: absolute; top: 0; left: 0; width: 170px; height: 150px; display: flex; flex-direction: column; justify-content: center; align-items: center; background-color: var(--es-block-bg); font-size: 22px; font-weight: 600; }
</style>The component version simplifies usage:
<template>
<SeamlessScroll class="es-center-bottom">
<div v-for="item in 10" class="es-bottom-item">{{ item }}</div>
</SeamlessScroll>
</template>
<script setup lang='ts'>
import SeamlessScroll from '@/components/SeamlessScroll.vue'
</script>By default the component scrolls horizontally; set :option="{ direction: 'vertical' }" for vertical scrolling.
Conclusion
The article covered the implementation of entry animations and seamless scrolling, providing reusable code and component wrappers that can be customized for any big‑screen Vue project.
For more details, explore the GitHub repository and the online demo links provided above.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.