0
1

【備忘録】slicksliderと<details>タグの相互作用

Last updated at Posted at 2024-09-17

やりたい事

sliderの中に、アコーディオン(detailsタグ使用)を入れ、開いたままスライドした時に閉じてほしい

書いたソース

HTML
<ul class="slider">
    <li>
        <img class="slider-price-img" src="" alt="">
        <img class="slider-main-img" src="" alt="">
        <img class="slider-main-txt" src="" alt="">
        <details>
            <summary></summary>
            <div class="details-open"><img loading="lazy" src="" alt=""></div>
        </details>
    </li>

    <li>
        <img class="slider-price-img" src="" alt="">
        <img class="slider-main-img" src="" alt="">
        <img class="slider-main-txt" src="" alt="">
        <details>
            <summary></summary>
            <div class="details-open"><img loading="lazy" src="" alt=""></div>
        </details>
    </li>

    <li>
        <img class="slider-price-img" src="" alt="">
        <img class="slider-main-img" src="" alt="">
        <img class="slider-main-txt" src="" alt="">
        <details>
            <summary></summary>
            <div class="details-open"><img loading="lazy" src="" alt=""></div>
        </details>
    </li>
   
    <!--/slider-->
</ul>
JavaScript
   $('.slider').on('beforeChange', function (event, slick, currentSlide, nextSlide) {
            $('details[open]').removeAttr('open');
        });
        $('.slider').slick({
            autoplay: false,//自動的に動き出すか。初期値はfalse。
            infinite: true,//スライドをループさせるかどうか。初期値はtrue。
            speed: 300,//スライドのスピード。初期値は300。
            slidesToShow: 3,//スライドを画面に3枚見せる
            slidesToScroll: 1,//1回のスクロールで1枚の写真を移動して見せる
            prevArrow: '<div class="slick-prev"></div>',//矢印部分PreviewのHTMLを変更
            nextArrow: '<div class="slick-next"></div>',//矢印部分NextのHTMLを変更
            centerMode: true,//要素を中央ぞろえにする
            variableWidth: true,//幅の違う画像の高さを揃えて表示
            dots: false,//下部ドットナビゲーションの表示
        });

バグ内容

スマホで1枚目のアコーディオンが開かない

原因

slicksliderのスライダーとdetailsタグの相互作用が発生
slicksliderが初期化される前に、details要素が正しく読み込まれていない可能性がある

対応策

色々試したが解決できなかったので、detailsタグは使わず、JSでアコーディオンを作る

修正したJavaScript

JavaScript
document.addEventListener('DOMContentLoaded', function() {
    $('.slider').slick({
        autoplay: false,
        infinite: true,
        speed: 300,
        slidesToShow: 3,
        slidesToScroll: 1,
        prevArrow: '<div class="slick-prev"></div>',
        nextArrow: '<div class="slick-next"></div>',
        centerMode: true,
        variableWidth: true,
        dots: false,
    });

    let currentSlide = 0;

    // スライド変更時にアコーディオンを閉じる
    $('.slider').on('beforeChange', function(event, slick, currentSlideIndex, nextSlideIndex) {
        if (currentSlideIndex !== nextSlideIndex) {
            closeAllAccordions();
        }
        currentSlide = nextSlideIndex;
    });

    // アコーディオンヘッダーのクリックイベント
    $('.accordion-header').on('click', function(e) {
        e.preventDefault();
        const content = $(this).next('.accordion-content');
        const isOpen = $(this).hasClass('open');

        // 全てのアコーディオンを閉じる
        closeAllAccordions();

        // クリックされたアコーディオンを開閉する
        if (!isOpen) {
            $(this).addClass('open');
            content.slideDown();
        }
    });

    // 全てのアコーディオンを閉じる関数
    function closeAllAccordions() {
        $('.accordion-header').removeClass('open');
        $('.accordion-content').slideUp();
    }

});

ソースの解説

addEventListener

JavaScript
document.addEventListener('DOMContentLoaded', function() {...})

説明: ページが読み込まれた時点で、指定した関数を実行するイベントリスナーです。
目的: ページのHTML要素が完全にロードされた後にスクリプトを実行するようにして、DOM操作の準備が整った状態で動作させるために使います。

スライダーを初期化

JavaScript
$('.slider').slick({...})

説明: ここでは、slickというライブラリを使ってスライダー(スライドショー)を初期化しています。

スライダーを初期化

JavaScript
$('.slider').slick({...})

説明: ここでは、slickというライブラリを使ってスライダー(スライドショー)を初期化しています。

設定内容:
autoplay: false:自動再生しない設定。
infinite: true:無限にスライドが繰り返される設定。
speed: 300:スライドの速度を300msに設定。
slidesToShow: 3:一度に表示するスライド数を3に設定。
slidesToScroll: 1:1回の操作で1つのスライドをスクロール。
centerMode: true:スライドをセンターに配置。
variableWidth: true:各スライドの幅を柔軟に変更可能にする。
dots: false:ドットナビゲーションを表示しない。

スライダーを初期化

JavaScript
let currentSlide = 0;

説明: 現在表示されているスライドのインデックス(番号)を保持するための変数です。
目的: スライドが変更されるときにその情報を追跡するために使います。

現在開いているアコーディオンを閉じる

JavaScript
 $('.slider').on('beforeChange', function(event, slick, currentSlideIndex, nextSlideIndex) {
        if (currentSlideIndex !== nextSlideIndex) {
            closeAllAccordions();
        }
        currentSlide = nextSlideIndex;
    });

説明: slickライブラリにより、スライドが変更される直前に発生するイベントです。ここで、スライドが変わる前に何か処理をしたい場合に使います。

目的: 次のスライドに移る前に、現在開いているアコーディオンを閉じるための処理を実行しています。

引数:
event: イベントオブジェクト。
slick: スライダーに関する情報。
currentSlideIndex: 現在のスライドのインデックス番号。
nextSlideIndex: 次に表示されるスライドのインデックス番号。
if (currentSlideIndex !== nextSlideIndex) { closeAllAccordions(); }:

スライドが変更される場合、全てのアコーディオンを閉じる関数(closeAllAccordions)を呼び出しています。
currentSlide = nextSlideIndex;:

次のスライドが表示された後、そのインデックスをcurrentSlideに更新して記録します。

アコーディオンのクリック時の処理

JavaScript
   $('.accordion-header').on('click', function(e) {
        e.preventDefault();
        const content = $(this).next('.accordion-content');
        const isOpen = $(this).hasClass('open');

        // 全てのアコーディオンを閉じる
        closeAllAccordions();

        // クリックされたアコーディオンを開閉する
        if (!isOpen) {
            $(this).addClass('open');
            content.slideDown();
        }
    });

説明: アコーディオンのヘッダー部分がクリックされたときに発生するイベントです。

e.preventDefault();: クリックによるデフォルトの動作(例えば、リンクに飛ぶ動作など)を無効にします。

const content = $(this).next('.accordion-content');:

クリックされた要素(this)に続く次のアコーディオンのコンテンツ部分(accordion-contentクラス)を取得します。
const isOpen = $(this).hasClass('open');:

このアコーディオンがすでに開かれているか(openクラスを持っているか)どうかを確認します。
closeAllAccordions();:

クリックされたときに全てのアコーディオンを閉じます。
if (!isOpen) { $(this).addClass('open'); content.slideDown(); }:

もしアコーディオンが閉じている場合は、openクラスを追加して、アコーディオンコンテンツをスライドダウンで開きます。

全てのアコーディオンを閉じる

JavaScript
    function closeAllAccordions() {
        $('.accordion-header').removeClass('open');
        $('.accordion-content').slideUp();
    }

説明: 全てのアコーディオンを閉じる関数です。
$('.accordion-header').removeClass('open');: 全てのアコーディオンヘッダーからopenクラスを削除します(つまり、開かれているアコーディオンを閉じます)。
$('.accordion-content').slideUp();: 全てのアコーディオンコンテンツをスライドアップして非表示にします。

0
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1