🎭 Transition トランジションアニメーション - インターフェースを活気づけよう!
🌟 アニメーション魔法使い:あなたのアプリに生命力を注入し、あらゆるインタラクションに驚きを与えましょう!
✨ Transition とは?
Transition は Vant が提供するトランジションアニメーションコンポーネントで、優雅なダンサーのように、要素の表示・非表示にスムーズなアニメーション効果を追加します。フェードイン/フェードアウト、スライド展開、スケール変換など、あらゆるアニメーションでインターフェースを生き生きとさせることができます!
🎯 主な特徴:
- 🎨 豊富なアニメーション:多くの組み込みトランジション効果
- ⚡ パフォーマンス最適化:CSS3 transform ベース、スムーズで滑らか
- 🔧 使いやすい:1つのコンポーネントで全てのアニメーションニーズを解決
- 🎛️ 高度なカスタマイズ:アニメーション時間とイージング関数のカスタマイズをサポート
🚀 クイックスタート
📦 基本的な使い方
最もシンプルなフェードイン/フェードアウト効果:
vue
<template>
<div>
<!-- 🎯 制御ボタン -->
<van-button @click="show = !show" type="primary">
{{ show ? '非表示' : '表示' }}
</van-button>
<!-- ✨ トランジションアニメーション -->
<van-transition :show="show">
<div class="content">
🎉 Hello Vant Transition!
</div>
</van-transition>
</div>
</template>
<script setup>
import { ref } from 'vue';
const show = ref(false);
</script>
<style>
.content {
width: 200px;
height: 100px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
margin-top: 16px;
}
</style>🎨 アニメーションの種類
🌟 組み込みアニメーション効果
Vant は豊富な組み込みアニメーション効果を提供しています:
| アニメーション名 | 効果の説明 | 適用シーン |
|---|---|---|
fade | フェードイン/フェードアウト | 🌅 汎用トランジション、優雅で自然 |
fade-up | 上方向へのフェード | 📱 モバイル端末向け、ジェスチャーに合わせる |
fade-down | 下方向へのフェード | 🔽 ドロップダウンメニュー、通知など |
fade-left | 左方向へのフェード | ⬅️ サイドバー、引き出しなど |
fade-right | 右方向へのフェード | ➡️ コンテンツ切り替え、ナビゲーションなど |
slide-up | 上方向へのスライド | 📋 ボトムポップアップ、操作パネル |
slide-down | 下方向へのスライド | 📢 トップ通知、プルリフレッシュ |
slide-left | 左方向へのスライド | 📄 ページ切り替え、カードスライド |
slide-right | 右方向へのスライド | 🔄 戻る操作、サイドスライドメニュー |
🎪 アニメーション効果のデモ
vue
<template>
<div class="demo-container">
<!-- 🎛️ アニメーションセレクタ -->
<van-field
v-model="selectedAnimation"
is-link
readonly
label="アニメーションを選択"
placeholder="アニメーション効果を選択してください"
@click="showPicker = true"
/>
<van-popup v-model:show="showPicker" position="bottom">
<van-picker
:columns="animationOptions"
@confirm="onConfirm"
@cancel="showPicker = false"
/>
</van-popup>
<!-- 🎯 制御ボタン -->
<van-button
@click="show = !show"
type="primary"
block
style="margin: 16px 0;"
>
{{ show ? 'アニメーションを非表示' : 'アニメーションを表示' }}
</van-button>
<!-- ✨ アニメーションデモエリア -->
<div class="animation-stage">
<van-transition :show="show" :name="selectedAnimation">
<div class="demo-box">
<div class="animation-name">{{ selectedAnimation }}</div>
<div class="animation-desc">{{ getAnimationDesc(selectedAnimation) }}</div>
</div>
</van-transition>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
const show = ref(false);
const showPicker = ref(false);
const selectedAnimation = ref('fade');
const animationOptions = [
{ text: 'フェードイン/フェードアウト (fade)', value: 'fade' },
{ text: '上方向へのフェード (fade-up)', value: 'fade-up' },
{ text: '下方向へのフェード (fade-down)', value: 'fade-down' },
{ text: '左方向へのフェード (fade-left)', value: 'fade-left' },
{ text: '右方向へのフェード (fade-right)', value: 'fade-right' },
{ text: '上方向へのスライド (slide-up)', value: 'slide-up' },
{ text: '下方向へのスライド (slide-down)', value: 'slide-down' },
{ text: '左方向へのスライド (slide-left)', value: 'slide-left' },
{ text: '右方向へのスライド (slide-right)', value: 'slide-right' },
];
const onConfirm = ({ selectedValues }) => {
selectedAnimation.value = selectedValues[0];
showPicker.value = false;
};
const getAnimationDesc = (name) => {
const descriptions = {
'fade': '🌅 優雅なフェードイン/フェードアウト',
'fade-up': '📱 上方向へのフェード、モバイル端末向け',
'fade-down': '🔽 下方向へのフェード、通知に最適',
'fade-left': '⬅️ 左方向へのフェード、サイドバー専用',
'fade-right': '➡️ 右方向へのフェード、コンテンツ切り替え',
'slide-up': '📋 上方向へのスライド、ボトムポップアップ',
'slide-down': '📢 下方向へのスライド、トップ通知',
'slide-left': '📄 左方向へのスライド、ページ切り替え',
'slide-right': '🔄 右方向へのスライド、戻る操作',
};
return descriptions[name] || '✨ 美しいアニメーション効果';
};
</script>
<style>
.demo-container {
padding: 16px;
}
.animation-stage {
min-height: 200px;
display: flex;
align-items: center;
justify-content: center;
background: #f7f8fa;
border-radius: 8px;
margin-top: 16px;
}
.demo-box {
width: 200px;
height: 120px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
}
.animation-name {
font-size: 16px;
font-weight: bold;
margin-bottom: 8px;
}
.animation-desc {
font-size: 12px;
opacity: 0.8;
text-align: center;
}
</style>⚙️ 高度な設定
🎛️ アニメーションの長さをカスタマイズ
vue
<template>
<div>
<!-- 🐌 低速アニメーション (1秒) -->
<van-transition :show="show1" :duration="1000">
<div class="slow-box">低速アニメーション (1s)</div>
</van-transition>
<!-- ⚡ 高速アニメーション (200ms) -->
<van-transition :show="show2" :duration="200">
<div class="fast-box">高速アニメーション (0.2s)</div>
</van-transition>
<!-- 🎯 異なる表示/非表示の長さ -->
<van-transition
:show="show3"
:duration="{ enter: 500, leave: 300 }"
>
<div class="custom-box">カスタム長さ</div>
</van-transition>
</div>
</template>🎨 アニメーション効果をカスタマイズ
あなた独自のアニメーション効果を作成しましょう:
vue
<template>
<van-transition :show="show" name="my-custom">
<div class="custom-content">カスタムアニメーション</div>
</van-transition>
</template>
<style>
/* 🎭 カスタムアニメーションクラス名 */
.my-custom-enter-active,
.my-custom-leave-active {
transition: all 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.my-custom-enter-from {
opacity: 0;
transform: scale(0.8) rotate(-10deg);
}
.my-custom-leave-to {
opacity: 0;
transform: scale(1.2) rotate(10deg);
}
/* 🌟 効果を追加 */
.custom-content {
background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
color: white;
padding: 20px;
border-radius: 12px;
text-align: center;
box-shadow: 0 8px 32px rgba(255, 107, 107, 0.3);
}
</style>🎪 実際の使用シーン
📱 モバイル端末向けポップアップ
vue
<template>
<div>
<!-- 🎯 トリガーボタン -->
<van-button @click="showModal = true" type="primary" block>
ポップアップを開く
</van-button>
<!-- 🌟 オーバーレイ -->
<van-transition :show="showModal">
<div class="modal-overlay" @click="showModal = false">
<!-- 📋 ポップアップコンテンツ -->
<van-transition :show="showModal" name="slide-up">
<div class="modal-content" @click.stop>
<div class="modal-header">
<h3>🎉 美しいポップアップ</h3>
<van-icon name="cross" @click="showModal = false" />
</div>
<div class="modal-body">
<p>これは Transition コンポーネントを使用して作成されたポップアップの例です。</p>
<p>スムーズなアニメーション効果と優れたユーザーエクスペリエンスを備えています。</p>
</div>
<div class="modal-footer">
<van-button @click="showModal = false" type="default">
キャンセル
</van-button>
<van-button @click="showModal = false" type="primary">
確認
</van-button>
</div>
</div>
</van-transition>
</div>
</van-transition>
</div>
</template>
<script setup>
import { ref } from 'vue';
const showModal = ref(false);
</script>
<style>
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: flex-end;
z-index: 1000;
}
.modal-content {
background: white;
border-radius: 16px 16px 0 0;
width: 100%;
max-height: 70vh;
overflow: hidden;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 20px;
border-bottom: 1px solid #eee;
}
.modal-body {
padding: 20px;
line-height: 1.6;
}
.modal-footer {
padding: 16px 20px;
display: flex;
gap: 12px;
border-top: 1px solid #eee;
}
</style>🔄 ページ切り替えアニメーション
vue
<template>
<div class="page-container">
<!-- 🧭 ナビゲーションバー -->
<van-nav-bar
:title="currentPage.title"
left-arrow
@click-left="goBack"
/>
<!-- 📄 ページコンテンツ -->
<div class="page-content">
<van-transition
:show="true"
:name="transitionName"
mode="out-in"
>
<component :is="currentPage.component" :key="currentPage.name" />
</van-transition>
</div>
<!-- 🎯 ページ切り替えボタン -->
<div class="page-controls">
<van-button
v-for="page in pages"
:key="page.name"
@click="navigateTo(page)"
:type="currentPage.name === page.name ? 'primary' : 'default'"
size="small"
>
{{ page.title }}
</van-button>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
const currentPageIndex = ref(0);
const transitionName = ref('slide-right');
const pages = [
{ name: 'home', title: 'ホーム', component: 'PageHome' },
{ name: 'about', title: '概要', component: 'PageAbout' },
{ name: 'contact', title: 'お問い合わせ', component: 'PageContact' },
];
const currentPage = computed(() => pages[currentPageIndex.value]);
const navigateTo = (page) => {
const newIndex = pages.findIndex(p => p.name === page.name);
const oldIndex = currentPageIndex.value;
// 🎭 ナビゲーションの方向に応じてアニメーションを選択
transitionName.value = newIndex > oldIndex ? 'slide-left' : 'slide-right';
currentPageIndex.value = newIndex;
};
const goBack = () => {
if (currentPageIndex.value > 0) {
transitionName.value = 'slide-right';
currentPageIndex.value--;
}
};
</script>🎯 API リファレンス
Props
| パラメータ | 説明 | タイプ | デフォルト値 |
|---|---|---|---|
show | コンポーネントを表示するかどうか | boolean | false |
name | アニメーションの種類 | string | 'fade' |
duration | アニメーションの長さ(ミリ秒) | number | object | 300 |
appear | 初期レンダリング時にトランジションを使用するかどうか | boolean | false |
Events
| イベント名 | 説明 | コールバックパラメータ |
|---|---|---|
before-enter | 表示前にトリガー | - |
enter | 表示中にトリガー | el: Element |
after-enter | 表示後にトリガー | - |
before-leave | 非表示前にトリガー | - |
leave | 非表示中にトリガー | el: Element |
after-leave | 非表示後にトリガー | - |
アニメーションの長さの設定
typescript
// 🕐 統一長さ
duration: 500
// 🎭 表示と非表示の長さを個別に設定
duration: {
enter: 300,
leave: 500
}💡 ベストプラクティス
🎨 アニメーション選択ガイド
| シーン | 推奨アニメーション | 理由 |
|---|---|---|
| 🔔 通知 | fade-down | 上部から自然に出現し、ユーザーの期待に合う |
| 📋 ボトムポップアップ | slide-up | 下部からスライド表示、モバイル端末の標準操作 |
| 🎭 モーダルダイアログ | fade | シンプルで優雅、注意を分散させない |
| 📄 ページ切り替え | slide-left/right | 明確な方向性、ナビゲーション体験を向上 |
| 🎯 ツールチップ | fade-up | 軽量アニメーション、迅速な応答 |
⚡ パフォーマンス最適化のコツ
vue
<template>
<!-- ✅ 推奨:v-show を Transition と組み合わせる -->
<van-transition :show="visible">
<div v-show="visible" class="content">コンテンツ</div>
</van-transition>
<!-- ❌ 避ける:頻繁な DOM の作成と破棄 -->
<van-transition :show="visible">
<div v-if="visible" class="content">コンテンツ</div>
</van-transition>
</template>
<script setup>
// 🎯 適切なアニメーションの長さを使用
const duration = {
enter: 250, // 表示は少し速く、応答性を高める
leave: 200 // 非表示はより速く、待ち時間を減らす
};
// 🔧 複雑すぎるアニメーションを避ける
const simpleTransition = 'fade'; // ✅ シンプルで効率的
const complexTransition = 'bounce-scale-rotate'; // ❌ 複雑すぎる
</script>🎪 アニメーション組み合わせのコツ
vue
<template>
<!-- 🌟 多層アニメーション効果 -->
<van-transition :show="show" name="fade">
<div class="container">
<van-transition :show="show" name="slide-up" :duration="400">
<div class="header">タイトルエリア</div>
</van-transition>
<van-transition :show="show" name="slide-up" :duration="500">
<div class="content">コンテンツエリア</div>
</van-transition>
<van-transition :show="show" name="slide-up" :duration="600">
<div class="footer">フッターエリア</div>
</van-transition>
</div>
</van-transition>
</template>🔧 よくある質問
❓ アニメーションが効かない?
🔍 チェックリスト:
- ✅
show属性が正しくバインドされているか確認 - ✅ CSS スタイルが上書きされていないか確認
- ✅ アニメーション名が正しいか検証
- ✅ 要素に明確なサイズが設定されているか確認
vue
<!-- ❌ 問題の例 -->
<van-transition :show="visible">
<div style="display: none;">コンテンツ</div> <!-- display: none はアニメーションを阻止する -->
</van-transition>
<!-- ✅ 正しい例 -->
<van-transition :show="visible">
<div class="content">コンテンツ</div>
</van-transition>❓ 複雑なアニメーションを実現するには?
vue
<template>
<van-transition
:show="show"
name="custom-complex"
@before-enter="onBeforeEnter"
@enter="onEnter"
@after-enter="onAfterEnter"
>
<div class="complex-element">複雑なアニメーション</div>
</van-transition>
</template>
<script setup>
// 🎭 JavaScript フックを使用して複雑なアニメーションを実現
const onBeforeEnter = (el) => {
el.style.opacity = '0';
el.style.transform = 'scale(0.5) rotate(-180deg)';
};
const onEnter = (el) => {
el.offsetHeight; // 再レイアウトをトリガー
el.style.transition = 'all 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55)';
el.style.opacity = '1';
el.style.transform = 'scale(1) rotate(0deg)';
};
const onAfterEnter = (el) => {
console.log('🎉 アニメーション完了!');
};
</script>🌟 高度なテクニック
🎨 カスタムイージング関数
css
/* 🎭 独自のアニメーション感覚を作る */
.my-transition-enter-active {
transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.my-transition-leave-active {
transition: all 0.3s cubic-bezier(0.55, 0.085, 0.68, 0.53);
}
/* 🌟 バウンス効果 */
.bounce-enter-active {
animation: bounce-in 0.5s;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}🔄 アニメーションシーケンス
vue
<template>
<div class="sequence-container">
<van-transition
v-for="(item, index) in items"
:key="item.id"
:show="show"
name="slide-up"
:duration="300"
:style="{ transitionDelay: `${index * 100}ms` }"
>
<div class="sequence-item">{{ item.text }}</div>
</van-transition>
</div>
</template>
<script setup>
const items = [
{ id: 1, text: '最初の要素' },
{ id: 2, text: '2番目の要素' },
{ id: 3, text: '3番目の要素' },
];
</script>関連ドキュメント 📚
🎯 コアコンポーネント
- Popup ポップアップ - ポップアップコンテナ、トランジションアニメーションとよく組み合わせて使用
- Dialog ダイアログ - ダイアログコンポーネント、優雅なトランジション効果を内蔵
- ActionSheet アクションシート - ボトムアクションパネル、スライドインアニメーションを使用
- Overlay オーバーレイ - 背景マスク、フェードイン/フェードアウト効果をサポート
🎨 インタラクティブコンポーネント
- Swipe カルーセル - カルーセルコンポーネント、スライドトランジションアニメーションをサポート
- Tab タブ - タブ切り替え、トランジションアニメーションと組み合わせ可能
- Collapse 折りたたみパネル - 折りたたみ展開アニメーション効果
- NoticeBar 通知バー - スクロール通知、スライドアニメーションをサポート
🔔 フィードバックコンポーネント
- Toast トースト - メッセージ提示、複数のトランジション効果を内蔵
- Notify 通知 - トップ通知、スライドダウンアニメーションを使用
- Loading ローディング - ローディング状態、フェードイン/フェードアウトをサポート
⚡ 高度な機能
- ConfigProvider グローバル設定 - アニメーションテーマと長さを統一的に設定
- Locale 国際化 - 複数言語環境でのアニメーション設定