Swiperで無限ループスライダーを作る際の注意点

Cocoonカスタマイズ集
この記事は約10分で読めます。
記事内に広告が含まれています。

拡張:マウスオーバーでスライドが停止させる方法

マウスカーソルがスライダーに乗ったとき、スライダーを停止します。

完成イメージ

実装手順

以下のコードを、前述のコードに追加します。

document.addEventListener('DOMContentLoaded', function () {
  // マウスオーバー制御の対象となるすべてのSwiper要素を取得
  const pauseTargetElements = document.querySelectorAll('.swiper');

  // 対象要素が存在しない場合は処理対象外
  if (!pauseTargetElements || pauseTargetElements.length === 0) {
    return;
  }

  // 各要素にマウスイベントを設定
  pauseTargetElements.forEach(function (swiperElement) {
    // Swiper要素またはSwiperインスタンスが存在しない場合は処理対象外
    if (!swiperElement || !swiperElement.swiperInstance) {
      return;
    }

    const mySwiper = swiperElement.swiperInstance;
    const transitionSpeed = parseFloat(swiperElement.dataset.transitionSpeed) || 5000;

    // マウスオーバー・アウト時のイベントを設定
    swiperElement.addEventListener('mouseover', function (event) {
      handleMouseOverOut(event, mySwiper, swiperElement, transitionSpeed);
    });

    swiperElement.addEventListener('mouseout', function (event) {
      handleMouseOverOut(event, mySwiper, swiperElement, transitionSpeed);
    });
  });

  /**
   * スライドの幅と左右マージンの合計値を取得
   *
   * @param {HTMLElement} slide - 対象のスライド要素
   * @return {number} マージンを含むスライドの合計幅
   */
  function getTotalSlideWidth(slide) {
    // スライド要素が存在しない場合は処理対象外
    if (!slide) {
      return 0;
    }

    const marginLeft = parseFloat(slide.style.marginLeft) || 0;     // 左マージンを取得
    const marginRight = parseFloat(slide.style.marginRight) || 0;   // 右マージンを取得
    const slideWidth = slide.offsetWidth || 0;                      // スライドの幅を取得

    return marginLeft + marginRight + slideWidth;                   // 合計幅を返す
  }

  /**
   * マウスオーバー・アウト時のSwiper制御処理
   *
   * @param {Event} event - イベントオブジェクト
   * @param {object} mySwiper - 対象のSwiperインスタンス
   * @param {HTMLElement} swiperElement - 対象のスライダー要素
   * @param {number} transitionSpeed - トランジション速度
   * @return {void}
   */
  function handleMouseOverOut(event, mySwiper, swiperElement, transitionSpeed) {
    // 必須パラメータが存在しない場合は処理対象外
    if (!event || !mySwiper || !swiperElement) {
      return;
    }

    // 現在のスライド位置を取得
    const currentTranslate = mySwiper.getTranslate();

    switch (event.type) {
      case 'mouseover':
        // マウスオーバー時にスライド位置を固定
        mySwiper.setTranslate(currentTranslate);  // 現在の位置を保持
        mySwiper.setTransition(0);                // トランジションを無効化
        break;

      case 'mouseout':
        // 対象要素内のアクティブスライドを取得
        const activeSlide = swiperElement.querySelector('.swiper-slide-active');

        // アクティブスライドが存在しない場合は処理対象外
        if (!activeSlide) {
          return;
        }

        // アクティブスライドの合計幅を取得
        const totalSlideWidth = getTotalSlideWidth(activeSlide);

        // 合計幅が取得できない場合は処理対象外
        if (totalSlideWidth <= 0) {
          return;
        }

        const translateDiff = -totalSlideWidth - (currentTranslate % totalSlideWidth);  // 移動差分を計算
        const transitionDuration = translateDiff / -activeSlide.offsetWidth;            // トランジションの持続時間を計算

        // トランジションを適用
        mySwiper.setTranslate(currentTranslate + translateDiff);        // 新しい位置にスライドを移動
        mySwiper.setTransition(transitionSpeed * transitionDuration);    // スライドの移動にかける時間を設定
        break;
    }
  }
});

解説

  • getTotalSlideWidth関数
    スライド要素本体の幅に加えて、左右に設定されているCSSマージンを取得して足し合わせる。 スライド1枚分が占める「正確な横幅」を計算するために行う。
  • handleMouseOverOut関数
    マウスオーバー状態(乗った時・外れた時)に応じて、アニメーションの「停止」と「スムーズな再開」を制御する。
    • mouseover(マウスが乗った時)
      • getTranslate()で現在の正確な表示位置を取得する。
      • setTranslate()でその位置に固定し、setTransition(0)でアニメーションを即座に停止させる。
    • mouseout(マウスが外れた時)
      • .swiper-slide-activeから現在アクティブなスライドを取得する。
      • getTotalSlideWidth()を呼び出し、スライド1枚分の合計幅を算出する。
      • 現在位置(currentTranslate)とスライド幅を元に、次の基準位置までの残りの移動距離(translateDiff)を計算する。
      • 移動距離とスライド幅の比率から、自然な速度で追いつくためのアニメーション時間(transitionDuration)を割り出す。
      • setTranslate()で次の目的地を設定し、setTransition()で計算した時間を適用して滑らかに連続再生を再開させる。

拡張:画面内に入ったら動作させる方法

スライダーが画面に50%入ったときに動作します。

実装手順

以下のコードを、前述のコードに追加します。

document.addEventListener('DOMContentLoaded', function () {
  // 監視対象となるすべてのSwiper要素を取得
  const observeTargetElements = document.querySelectorAll('.swiper');

  // 対象要素が存在しない場合は処理対象外
  if (!observeTargetElements || observeTargetElements.length === 0) {
    return;
  }

  // 要素の表示状態を監視
  const observer = new IntersectionObserver(handleIntersection, { threshold: 0.5 });

  // 各要素を初期化して監視対象に登録
  observeTargetElements.forEach(function (swiperElement) {
    // Swiper要素またはSwiperインスタンスが存在しない場合は処理対象外
    if (!swiperElement || !swiperElement.swiperInstance) {
      return;
    }

    // 初期状態でオートプレイを停止
    swiperElement.swiperInstance.autoplay.stop();

    // Swiper要素を監視対象に登録
    observer.observe(swiperElement);
  });

  /**
   * IntersectionObserverのコールバック処理
   *
   * @param {IntersectionObserverEntry[]} entries - 監視対象のエントリー配列
   * @return {void}
   */
  function handleIntersection(entries) {
    // エントリーが存在しない場合は処理対象外
    if (!entries || entries.length === 0) {
      return;
    }

    entries.forEach(function (entry) {
      // エントリー、対象要素、Swiperインスタンスが存在しない場合は処理対象外
      if (!entry || !entry.target || !entry.target.swiperInstance) {
        return;
      }

      const mySwiper = entry.target.swiperInstance;

      // 要素がビューポート内に入った場合
      if (entry.isIntersecting) {
        // オートプレイを開始
        mySwiper.autoplay.start();
      } else {
        // オートプレイを停止
        mySwiper.autoplay.stop();
      }
    });
  }
});

参考:WordPress 7.1におけるカスタムHTMLブロック内での編集可能ブロックのサポート

「カスタムHTML」ブロック

WordPress 7.1では、カスタムHTMLブロックの中に、静的なHTML(<div>タグなどの構造)と通常の編集可能なブロックを混在させて配置できるようになりました(図1参照)。

例えば、<div>タグで囲んだ中に画像ブロックを配置した場合、周囲の<div>タグやその他の静的なマークアップはエディタ上で操作不可(不活性)のまま表示されますが、内部に配置した画像ブロックは通常のブロックと同様にメニューから画像の差し替えなどの操作が行えます。

ただし、内部に配置したブロックはロックされており、移動・削除・兄弟ブロックの追加はできません。
周囲の構造はそのまま維持されます。

さいごに

今回紹介した方法を使えば、「Swiper.js」を使用して無限ループのスライダーを作成できます。
さらに、マウスオーバー時の動作停止や、画面内に入った際の自動再生といった高度な機能を簡単に実装できます。

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