メッセージ
ghost
pacman
PR

複数の通知メッセージをアニメーション演出で表示する方法

Cocoonカスタマイズ集
この記事は約9分で読めます。

完成イメージ

本ページに完成イメージを反映させます。

実装手順

以下の手順で実装します。

// テンプレート(通知エリア)の直後に追加
add_action('cocoon_part_after__tmp/notice', function () {
  $pacman_url = 'パックマン画像URL';
  $ghost_url  = 'お化け画像URL';
  ?>
  <div class="pacman-marquee">
    <div class="pacman-marquee__message">
      <img src="<?= esc_url($ghost_url); ?>" class="pacman-marquee__ghost" alt="ghost" />
    </div>
    <img src="<?= esc_url($pacman_url); ?>" alt="pacman" class="pacman-marquee__pacman" />
  </div>
  <?php
});


// フロント用JS・CSSを追加
add_action('wp_enqueue_scripts', function () {
  ob_start();
  ?>
  .pacman-marquee {
    align-items: center;
    background-color: #333;
    display: flex;
    height: 40px;
    overflow: hidden;
    position: relative;
  }

  .pacman-marquee__message {
    align-items: center;
    color: #fff;
    display: flex;
    font-size: 14px;
    position: absolute;
    white-space: nowrap;
  }

  .pacman-marquee__ghost {
    margin-right: 5px;
  }

  .pacman-marquee__pacman {
    position: absolute;
  }

  .pacman-marquee__char.eaten {
    opacity: 0;
  }
  <?php

  $handle = 'pacman-marquee';

  wp_register_style($handle, false);
  wp_enqueue_style($handle);
  wp_add_inline_style($handle, ob_get_clean());

  ob_start();
  ?>
  jQuery(function ($) {
    // 表示するメッセージ配列
    const messages = [
      "メッセージ1",
      "メッセージ2",
      "メッセージ3",
    ];

    // パックマンが文字を食べるスピード(ミリ秒)
    const EAT_INTERVAL = 250;

    // DOM要素取得
    const $textEl = $(".pacman-marquee__message");
    const $pacman = $(".pacman-marquee__pacman");
    const $container = $(".pacman-marquee");

    // 現在表示中のメッセージインデックス
    let currentIndex = 0;

    /**
     * パックマンのCSSスタイルを一括で適用
     *
     * @param {Object} styles 適用するCSSプロパティと値のオブジェクト
     * @returns {void}
     */
    function setPacmanStyle(styles) {
      $pacman.css(styles);
    }

    /**
     * パックマンの位置と表示状態をコンテナの右外側にリセットする
     *
     * @returns {void}
     */
    function resetPacman() {
      setPacmanStyle({
        transition: 'none',
        opacity: '1',
        left: $container.width() + 50 + "px",
        display: 'none'
      });
    }

    /**
     * 指定されたインデックスのメッセージを初期化しスライド表示
     *
     * @param {number} index 表示するメッセージのインデックス
     * @returns {void}
     */
    function showMessage(index) {
      // 文字列を1文字ずつに分解してspan要素に変換
      const spans = [...messages[index]].map(c => '<span class="pacman-marquee__char">' + c + '</span>').join('');

      // 既存の文字要素のみ削除(お化け画像などはそのまま)
      $textEl.find('.pacman-marquee__char').remove();

      // 新しい文字列を追加
      $textEl.append(spans);

      // メッセージ文字列を画面右外から初期配置
      $textEl.css({ transition: 'none', left: '100%' });

      // パックマン位置もリセット
      resetPacman();

      // 少し遅らせて左端までスライド
      setTimeout(() => {
        $textEl.css({ transition: 'left 6s linear', left: '0%' });
      }, 50);
    }

    /**
     * メッセージのスライド完了後にパックマンを登場させ、文字を右から順に食べるアニメーションを開始
     *
     * @returns {void}
     */
    function startAnimation() {
      const $charSpans = $textEl.find('.pacman-marquee__char');
      const containerLeft = $container[0].getBoundingClientRect().left;

      // 最後の文字の右端座標を取得
      const lastCharRight = $charSpans.last()[0].getBoundingClientRect().right;
      const targetLeft = lastCharRight - containerLeft + 15;

      // パックマンを右外から表示(位置リセット)
      setPacmanStyle({
        display: 'block',
        transition: 'none',
        left: $container.width() + 50 + "px",
        opacity: '1'
      });

      // 少し遅れて最後の文字の右へ移動
      setTimeout(() => {
        setPacmanStyle({ transition: 'left 0.5s linear', left: targetLeft + "px" });

        // 移動後、文字を1つずつ食べる処理を開始
        $pacman.off('transitionend').on('transitionend', function (e) {
          if (e.originalEvent.propertyName !== 'left') return;
          $pacman.off('transitionend');

          // 文字を逆順で処理(右→左に食べるため)
          const reversedChars = $($charSpans.get().reverse());
          let i = 0;

          /**
           * 次の文字の位置へ移動し、文字を透過処理しながら順に食していく再帰関数
           *
           * @returns {void}
           */
          function eatNext() {
            if (i >= reversedChars.length) {
              // 全部食べ終えたら次のメッセージへ
              resetPacman();
              currentIndex = (currentIndex + 1) % messages.length;
              showMessage(currentIndex);
              return;
            }

            // 次の文字の位置を取得(左からの距離)
            const $char = reversedChars.eq(i);
            const left = $char[0].getBoundingClientRect().left - containerLeft;

            // パックマンをその位置へ移動
            setPacmanStyle({
              transition: 'left ' + EAT_INTERVAL + 'ms linear',
              left: left + "px"
            });

            // 文字を食べた演出(透明にする)
            $char.addClass('eaten');

            i++;
            setTimeout(eatNext, EAT_INTERVAL);
          }

          eatNext();
        });
      }, 300);
    }

    // 最初のメッセージ表示
    showMessage(currentIndex);

    // テキストスライドが完了したらパックマン登場アニメーションを開始
    $textEl.on('transitionend', e => {
      if (e.originalEvent.propertyName === 'left') {
        startAnimation();
      }
    });
  });
  <?php
  wp_add_inline_script('jquery', ob_get_clean());
});

さいごに

今回紹介した方法を使えば、簡単に独自の通知メッセージをアニメーション付きで表示することができます。
視覚的な楽しさを加えることで、ユーザーの注目を集める効果も期待できます。
お知らせや重要な案内など、目立たせたい情報があるときにぜひ活用してみてください。

タイトルとURLをコピーしました