Implementing a Seamless Carousel with Vue: Dynamic Data Switching, Transition Effects, and Auto‑Play Controls
This tutorial explains how to build a seamless carousel in Vue by dynamically switching a data list, using the Transition component for enter/leave animations, adding an auto‑play timer, handling hover pause/resume, and solving visibility‑change flicker with concise CSS and JavaScript code.
The article introduces a common front‑end requirement – a carousel (轮播图) – and shows how to implement it without external UI libraries by writing custom Vue code.
Requirement Overview : Create a seamless carousel that continuously cycles through a list of items, with optional pause on hover and proper handling of page visibility changes.
Implementation Idea : The core concept is to dynamically change the displayed item index in a data array, letting Vue render the current item while the Transition component provides smooth enter and leave animations.
Data List Definition :
const list = ref([
{ name: 1, id: 1 },
{ name: 2, id: 2 },
{ name: 3, id: 3 }
]);Basic Template Rendering :
<template>
<div>{{ list[index] }}</div>
</template>
<script setup>
const index = ref(0);
const list = ref([{ name: 1, id: 1 }, { name: 2, id: 2 }, { name: 2, id: 2 }]);
</scriptp>Dynamic List Rendering with v‑for :
<template>
<div v‑for="(item, i) in list" :key="i">
<div v‑show="i === selectIndex">Card custom content</div>
</div>
</template>
<script setup>
const selectIndex = ref(0);
const list = ref([
{ name: "卡片1", id: 1 },
{ name: "卡片1", id: 2 },
{ name: "卡片1", id: 2 }
]);
let timer = null;
const timeFuc = () => {
timer = setInterval(() => {
if (selectIndex.value >= list.value.length - 1) {
selectIndex.value = 0;
} else {
selectIndex.value++;
}
}, 5000);
};
timeFuc();
</scriptp>Using Vue's Transition Component to animate entry and exit:
<template>
<div class="main-content">
<Transition v‑for="(item, i) in list" :key="selectIndex">
<div class="banner-scroll-wrap" v‑show="i === selectIndex">Card custom content</div>
</Transition>
</div>
</template>
<script setup>
// same data and timer logic as above
</scriptp>The selectIndex changes dynamically, causing the Transition component to trigger its enter and leave CSS classes.
CSS for Animation (scoped Less):
<style lang="less" scoped>
.main-content { position: relative; height: 100%;
.banner-scroll-wrap { position: absolute; top:0; bottom:0; left:0; right:0; }
}
.v-enter-from { transform: translateX(100%); opacity: 0; }
.v-enter-active, .v-leave-active { transition: transform 600ms ease-in-out, opacity 600ms ease-in-out; }
.v-enter-to { transform: translateX(0); opacity: 1; }
.v-leave-from { transform: translateX(0); opacity: 1; }
.v-leave-to { transform: translateX(-100%); opacity: 0; }
</style>Pause and Resume on Hover :
<template>
<div class="main-content" @mouseenter="stop()" @mouseleave="start()">
</div>
</template>
<script setup>
const start = () => { if (timer) return; timeFuc(); };
const stop = () => { clearInterval(timer); timer = null; };
</scriptp>Handling Visibility Change to avoid flicker after switching browser tabs:
<script setup>
onMounted(() => {
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') { stop(); }
if (document.visibilityState === 'visible') { start(); }
});
});
onBeforeUnmount(() => stop());
</scriptp>The visibilitychange event pauses the timer when the page is hidden and resumes it when visible again.
Conclusion : By combining a reactive data list, Vue's Transition component, a simple interval timer, hover controls, and visibility handling, a seamless carousel with smooth left‑to‑right (or top‑to‑bottom by changing translateX to translateY ) can be built without external libraries.
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.