アコーディオンを素のJavaScriptで実装してみた

# はじめに
この記事は学習メモです。
こんな感じで書くと動くよ〜的な。
なので、もっと良い書き方とかあると思いますが、そんなときは優しく教えて下さい。
＿|＼○＿ｵﾈｶﾞｲｼﾔｧｧｧｧｧｽ!!

# 実装したもの
今回実装したのは、めちゃくちゃシンプルなアコーディオンです。
オレンジの部分をクリックするとその下にテキストが展開されて、
もう一回クリックすると閉まるっていうアレです。
こんな感じ↓
![スクリーンショット 2021-02-07 16.03.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001476/bb9316a0-ec60-4fcf-5609-23659d756230.png)

# コード
掻い摘んで説明していきます。
### HTML
```html
<dl class="accordion">
    <dt class="accordion__ttl">
        <button class="accordion__btn" type="button">クリックすると...</button>
    </dt>
    <dd class="accordion__body">
        <p class="accordion__txt">開いたーー</p>
    </dd>
    <dt class="accordion__ttl">
        <button class="accordion__btn" type="button">クリックすると...</button>
    </dt>
    <dd class="accordion__body">
        <p class="accordion__txt">開いたーー</p>
    </dd>
</dl>
```
`dt` が上のオレンジ部分
`dd` が下のテキスト部分
それぞれの中身に`button` と `p`
これが2セットあり、全体を `dl` で囲んであるという構造。
今回は `dt`（実際は`button`）を押すと、 `dd` が展開されるというもの。

### SCSS
```scss
.accordion__body + .accordion__ttl {
    margin-top: 20px;
}
.accordion__btn {
    position: relative;
    padding: 10px 40px 10px 15px;
    display: block;
    width: 100%;
    background-color: #e25c00;
    color: #fff;
    text-align: left;
    cursor: pointer;
    &::before {
        content: '';
        position: absolute;
        top: 50%;
        right: 15px;
        transform: translateY(-50%);
        display: block;
        width: 20px;
        height: 2px;
        background-color: currentColor;
    }
    &::after {
        content: '';
        position: absolute;
        top: 50%;
        right: 15px;
        transform: translateY(-50%) rotate(90deg);
        display: block;
        width: 20px;
        height: 2px;
        background-color: currentColor;
    }
    &--active {
        &::after {
            content: none;
        }
    }
}
.accordion__body {
    display: none;
    padding: 15px;
    border: 1px solid #ddd;
    &--active {
        display: block;
    }
}
```
大まかに説明すると、
1. ボタンのスタイル指定
2. 疑似要素で右側の＋マークを指定
3. 展開される部分のスタイル指定
4. クリック時の指定

ちなみに1行目の記述は、
2つ目以降のアコーディオンに `margin-top` を指定するものです。

```scss
.accordion__body + .accordion__ttl {
    margin-top: 20px;
}
```

### JS
```js
const accordionBtn = document.querySelectorAll('.accordion__btn');

for (let i = 0; i < accordionBtn.length; i++) {
    const element = accordionBtn[i];
    const parent = element.parentNode;
    const accordionBody = parent.nextElementSibling;
    element.addEventListener('click', ()=>{
        element.classList.toggle('accordion__btn--active');
        accordionBody.classList.toggle('accordion__body--active');
    });
}
```
クラス名が `accordion__btn` の要素をすべて取得

```js
const accordionBtn = document.querySelectorAll('.accordion__btn');
```

取得した要素1つずつを`element`に格納
↓
`element`の親要素（`dt`）を取得して`parent`に格納
↓
`parent`の直後の兄弟要素（`dd`）を取得して`accordionBody`に格納

```js
    const element = accordionBtn[i];
    const parent = element.parentNode;
    const accordionBody = parent.nextElementSibling;
```
最後に、クリックしたときに行われる処理を設定

```js
    element.addEventListener('click', ()=>{
        element.classList.toggle('accordion__btn--active');
        accordionBody.classList.toggle('accordion__body--active');
    });
```
クリックしたら、
`button`に`accordion__btn--active`
`dd`に`accordion__body--active`というクラスをつけたり外したり。

# 参考
https://css-architecture-perfect.guide/
https://wemo.tech/2101#index_id15