vue3 に animate.css を適用しアニメーションさせる

vue3 に animate.css を適用しアニメーションさせる

2024/04/29 00:00:00
Program
Git-Bash, Node, Vite, Vue, Bootstrap, Sass, SPA, Animate.css

前提 #

animate.css をインストールする #

$ npm install animate.css

animate.css を vue3 で使えるようにする #

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import './scss/styles.scss'
import 'animate.css/animate.min.css';  // 追加
import * as bootstrap from 'bootstrap'

const app = createApp(App)
app.use(router)
app.mount('#app')

カルーセル時にキャプションを移動させる #

カルーセルのベースソースは以下の公式サイトを参考にする
https://getbootstrap.jp/docs/5.3/components/carousel/

  • carousel 機能で3秒後にスライドを実行し続ける
    <div id="carouselTop" class="carousel slide" data-bs-ride="carousel" data-bs-interval="3000">
    
  • animate.css でスライドに合わせてキャプションをフェードインさせる
    <p class="fs-1 fw-bold animate__animated animate__fadeInDown">Welcome to Mamba</p>
    <p class="animate__animated animate__fadeInUp animation-delay-04">説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1</p>
    <button class="btn btn-primary animate__animated animate__fadeInUp animation-delay-08">詳細</button>
    
    • animate__animated animate__fadeInDown
      上から下に移動してくるアニメーション
    • animate__animated animate__fadeInUp
      下から上に移動してくるアニメーション
    • animation-delay-04
      animation-delay-08 も同じくアニメーションを遅延させる設定

      $emacs src/scss/styles.scss

      animation-delay: 0.4s;  // 0.4秒後にアニメーション
      animation-delay: 0.8s;  // 0.4秒後にアニメーション
      

以下、サンプルコードまとめ

  • 画像パスは適当に合わせる必要がある

$ emacs src/components/home.vue

    ...
    <div id="carouselTop" class="carousel slide" data-bs-ride="carousel" data-bs-interval="3000">
      <div class="carousel-indicators">
        <button type="button" data-bs-target="#carouselTop" data-bs-slide-to="0" class="active" aria-current="true" aria-label="Slide 1"></button>
        <button type="button" data-bs-target="#carouselTop" data-bs-slide-to="1" aria-label="Slide 2"></button>
        <button type="button" data-bs-target="#carouselTop" data-bs-slide-to="2" aria-label="Slide 3"></button>
      </div>
      <div class="carousel-inner">
        <div class="carousel-item active">
          <img src="../assets/images/slides/slide-1.jpg" class="d-block w-100">
          <div class="carousel-caption ">
            <p class="fs-1 fw-bold animate__animated animate__fadeInDown">Welcome to Mamba</p>
            <p class="animate__animated animate__fadeInUp animation-delay-04">説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1説明1</p>
            <button class="btn btn-primary animate__animated animate__fadeInUp animation-delay-08">詳細</button>
          </div>
        </div>
        <div class="carousel-item">
          <img src="../assets/images/slides/slide-2.jpg" class="d-block w-100">
          <div class="carousel-caption ">
            <p class="fs-1 fw-bold animate__animated animate__fadeInDown">Lorem Ipsum Dolor</p>
            <p class="animate__animated animate__fadeInUp animation-delay-04">説明2説明2説明2説明2説明2説明2説明2説明2説明2説明2説明2説明2説明2説明2説明2説明2説明2説明2説明2説明2説明2説明2</p>
            <button class="btn btn-primary animate__animated animate__fadeInUp animation-delay-08">詳細</button>
          </div>
        </div>
        <div class="carousel-item">
          <img src="../assets/images/slides/slide-3.jpg" class="d-block w-100">
          <div class="carousel-caption ">
            <p class="fs-1 fw-bold animate__animated animate__fadeInDown">Sequi ea ut et est quaerat</p>
            <p class="animate__animated animate__fadeInUp animation-delay-04">説明3説明3説明3説明3説明3説明3説明3説明3説明3説明3説明3説明3説明3説明3説明3説明3説明3説明3説明3説明3説明3説明3</p>
            <button class="btn btn-primary animate__animated animate__fadeInUp animation-delay-08">詳細</button>
          </div>
        </div>
      </div>
      <button class="carousel-control-prev" type="button" data-bs-target="#carouselTop" data-bs-slide="prev">
        <span class="carousel-control-prev-icon" aria-hidden="true"></span>
        <span class="visually-hidden">Previous</span>
      </button>
      <button class="carousel-control-next" type="button" data-bs-target="#carouselTop" data-bs-slide="next">
        <span class="carousel-control-next-icon" aria-hidden="true"></span>
        <span class="visually-hidden">Next</span>
      </button>
    </div>
    ...

$ emacs src/scss/styles.scss

...
.animation-delay-04{
  animation-delay: 0.4s;
}

.animation-delay-08{
  animation-delay: 0.8s;
}
...

スクロールに合わせてアニメーションさせる #

bootstrapのカードをスクロールで画面内に入ってきた時にフェードインしてくるアニメーションを作成する
カードのベースソースは以下の公式サイトを参考にする
https://getbootstrap.jp/docs/5.3/components/card/

  • 指定したカードが画面内に入ってきた時にフェードインする設定
    独自に作成した scrollFadeIn クラスを指定
    <div class="container animate__animated scrollFadeIn">
    
  • 独自に作成した scrollFadeIn クラスを作成
    .scrollFadeIn{
      animation-delay: 0.2s; // 0.2秒後に発火
    }
    
  • scrollFadeIn クラスが画面内に入った場合、フェードインアニメーション発火
    const animation = 'animate__fadeInUp'; // 実行するアニメーション名
    const animateClass = '.scrollFadeIn'; // 複数の要素を選択するセレクター
    const elements = ref([]);
    
    // Intersection Observer のコールバック関数
    const handleIntersection = (entries, observer) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          // 要素が画面内に入ったら fadeinup アニメーションを追加
          entry.target.classList.add(animation);
    
          // Intersection Observer を解除
          observer.unobserve(entry.target);
        }
      });
    };
    
    // Intersection Observer の作成
    const observer = new IntersectionObserver(handleIntersection);
    
    // 要素を監視
    onMounted(() => {
      elements.value = document.querySelectorAll(animateClass);
      elements.value.forEach((el) => observer.observe(el));
    });
    
    // アニメーションが終了したらクラスを削除
    elements.value.forEach((el) => {
      el.addEventListener('animationend', () => {
        el.classList.remove(animation);
      });
    });
    

以下、サンプルコードまとめ

$ emacs src/components/home.vue

<template>
...
<hr>
<br>
<div class="container animate__animated scrollFadeIn">
  <div class="card" style="width: 18rem;">
    <div class="card-body">
      <h5 class="card-title">Card title</h5>
      <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
      <a href="#" class="btn btn-primary">Go somewhere</a>
    </div>
  </div>
</div>
...
</template>

<script setup>
import { ref, onMounted } from 'vue';

const animation = 'animate__fadeInUp'; // 実行するアニメーション名
const animateClass = '.scrollFadeIn'; // 複数の要素を選択するセレクター
const elements = ref([]);

// Intersection Observer のコールバック関数
const handleIntersection = (entries, observer) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      // 要素が画面内に入ったら fadeinup アニメーションを追加
      entry.target.classList.add(animation);

      // Intersection Observer を解除
      observer.unobserve(entry.target);
    }
  });
};

// Intersection Observer の作成
const observer = new IntersectionObserver(handleIntersection);

// 要素を監視
onMounted(() => {
  elements.value = document.querySelectorAll(animateClass);
  elements.value.forEach((el) => observer.observe(el));
});

// アニメーションが終了したらクラスを削除
elements.value.forEach((el) => {
  el.addEventListener('animationend', () => {
    el.classList.remove(animation);
  });
});
</script>

$ emacs src/scss/styles.scss

...
    .scrollFadeIn{
      animation-delay: 0.2s; // 0.2秒後に発火
    }
...

参考URL #