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

# やりたい事

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


# 書いたソース

```html: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>
```


```js: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,//下部ドットナビゲーションの表示
        });
```
:::note alert
# バグ内容
### スマホで1枚目のアコーディオンが開かない

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

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

# 修正したJavaScript
```js: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();
    }

});
```
:::note info
# ソースの解説
:::


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


## スライダーを初期化
```js:JavaScript
$('.slider').slick({...})
```
説明: ここでは、slickというライブラリを使ってスライダー（スライドショー）を初期化しています。


## スライダーを初期化
```js:JavaScript
$('.slider').slick({...})
```
説明: ここでは、slickというライブラリを使ってスライダー（スライドショー）を初期化しています。

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

## スライダーを初期化
```js:JavaScript
let currentSlide = 0;
```
説明: 現在表示されているスライドのインデックス（番号）を保持するための変数です。
目的: スライドが変更されるときにその情報を追跡するために使います。

## 現在開いているアコーディオンを閉じる
```js: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に更新して記録します。


## アコーディオンのクリック時の処理
```js: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クラスを追加して、アコーディオンコンテンツをスライドダウンで開きます。


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