1. Vue Transition
<script setup lang="ts">
const isVisible = ref(true)
</script>
<template>
<button @click="isVisible = !isVisible">Toggle</button>
<Transition name="fade">
<div v-if="isVisible" class="box">Fade content</div>
</Transition>
<Transition name="slide" mode="out-in">
<div :key="currentTab">{{ currentTab }}</div>
</Transition>
</template>
<style>
.fade-enter-active, .fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from, .fade-leave-to {
opacity: 0;
}
.slide-enter-active, .slide-leave-active {
transition: all 0.3s ease;
}
.slide-enter-from {
transform: translateX(30px);
opacity: 0;
}
.slide-leave-to {
transform: translateX(-30px);
opacity: 0;
}
</style>
2. TransitionGroup
<script setup lang="ts">
const items = ref([1, 2, 3, 4, 5])
function addItem() {
const num = Math.max(...items.value) + 1
items.value.splice(Math.floor(Math.random() * items.value.length), 0, num)
}
function removeItem(item: number) {
items.value = items.value.filter(i => i !== item)
}
</script>
<template>
<button @click="addItem">Add</button>
<TransitionGroup name="list" tag="ul">
<li v-for="item in items" :key="item" @click="removeItem(item)">
{{ item }}
</li>
</TransitionGroup>
</template>
<style>
.list-enter-active, .list-leave-active {
transition: all 0.5s ease;
}
.list-enter-from, .list-leave-to {
opacity: 0;
transform: translateX(30px);
}
.list-move {
transition: transform 0.5s ease;
}
.list-leave-active {
position: absolute;
}
</style>
3. Page Transitions (Nuxt)
// nuxt.config.ts
export default defineNuxtConfig({
app: {
pageTransition: { name: 'page', mode: 'out-in' },
layoutTransition: { name: 'layout', mode: 'out-in' },
},
})
/* assets/css/transitions.css */
.page-enter-active, .page-leave-active {
transition: all 0.3s;
}
.page-enter-from, .page-leave-to {
opacity: 0;
filter: blur(1rem);
}
.layout-enter-active, .layout-leave-active {
transition: all 0.4s;
}
.layout-enter-from, .layout-leave-to {
opacity: 0;
transform: translateY(-20px);
}
<!-- Per-page custom transition -->
<script setup lang="ts">
definePageMeta({
pageTransition: {
name: 'rotate',
mode: 'out-in',
},
})
</script>
4. GSAP Integration
<script setup lang="ts">
import gsap from 'gsap'
const boxRef = ref<HTMLElement | null>(null)
onMounted(() => {
if (boxRef.value) {
gsap.from(boxRef.value, {
duration: 1,
y: 100,
opacity: 0,
ease: 'power3.out',
})
}
})
// Stagger animation
function animateList() {
gsap.from('.list-item', {
y: 50,
opacity: 0,
duration: 0.5,
stagger: 0.1,
ease: 'power2.out',
})
}
</script>
<template>
<div ref="boxRef" class="box">Animated box</div>
</template>
5. View Transitions API
// nuxt.config.ts
export default defineNuxtConfig({
app: {
viewTransition: true, // Enable View Transitions API
},
})
<template>
<!-- Assign transition name -->
<img
:src="post.image"
:style="{ viewTransitionName: `post-image-${post.id}` }"
/>
<h1 :style="{ viewTransitionName: `post-title-${post.id}` }">
{{ post.title }}
</h1>
</template>
Bài tiếp theo: Advanced Patterns & Custom Module — renderless, render functions, custom modules.