jQuery非依存のアコーディオン作ってみた

jQueryの`slideToggle()`はすごく便利ですが、頼りすぎるとエンジニア強度が下がってしまいます。
下がらないように、素のJavaScriptでも、アコーディオンを作ってみましょう。

## サンプルコード
こんな感じで作ってみました。

```js:JavaScript
const accordion = (
  // 初期値
  {
    target = 'js-ac',
    btn = 'js-ac_btn',
    content = 'js-ac_content',
    speed = 1.5,
    cssEase = 'ease-out'
  } = {}
) => {
  const TARGET = document.getElementsByClassName(target);
  const TARGET_LENGTH = TARGET.length;
  for (let i = 0; i < TARGET_LENGTH; i++) {
    let isShow = false;
    const CURRENT_TARGET = TARGET[i];
    const BTN = CURRENT_TARGET.getElementsByClassName(btn)[0];
    const CONTENT = CURRENT_TARGET.getElementsByClassName(content)[0];
    const MAX_HEIGHT = CONTENT.scrollHeight;
    const DURATION = MAX_HEIGHT * speed;
    CONTENT.style.transitionDuration = `${DURATION}ms`;
    CONTENT.style.transitionTimingFunction = cssEase;
    BTN.addEventListener('click', () => {
      CONTENT.style.height = isShow ? 0 : `${MAX_HEIGHT}px`;
      isShow = !isShow;
    });
  }
};

// 実行
accordion({
  // 初期値の上書き
  speed: 1, // 1で100px 100msのスピード
  cssEase: 'ease'
});

// 上書きなしで実行
// accordion();
```
```html:HTML

<div class="js-ac">
  <button class="js-ac_btn" type="button">ボタン</button>
  <div class="js-ac_content">
    <!-- コンテンツ -->
  </div>
</div>
```
```css:CSS

.js-ac {
  overflow: hidden;
}
.js-ac_content {
  height: 0;
  transition-property: height;
}
```

引数で初期値を上書きすることにより、CSSクラス名やイージング、スピードを調整できます。
では、それぞれの役割をみていきましょう。

## 解説
### 引数
```js:JavaScript
// 初期値
{
  target = 'js-ac',
  btn = 'js-ac_btn',
  content = 'js-ac_content',
  speed = 1.5,
  cssEase = 'ease-out'
} = {}
```

仮引数部分は、オブジェクトの分割代入を利用して初期値を設定しています。実行時、実引数にオブジェクト形式で記述することにより、初期値を上書きすることができます。

詳しい解説は、こちらをどうぞ。 
[【JavaScript】関数の引数をオブジェクト形式にして、さらに初期値を設定する。](https://qiita.com/otsukayuhi/items/5dfb407b124783a39f04)

### アコーディオン
```js:JavaScript
// .js-acを取得
const TARGET = document.getElementsByClassName(target);

// .js-acの数だけループ処理
const TARGET_LENGTH = TARGET.length;
for (let i = 0; i < TARGET_LENGTH; i++) {
  let isShow = false; // アコーディオンの開閉フラグ
  const CURRENT_TARGET = TARGET[i]; // 対象の.js-acクラス
  const BTN = CURRENT_TARGET.getElementsByClassName(btn)[0]; // 対象の.js-acクラス内のボタン要素
  const CONTENT = CURRENT_TARGET.getElementsByClassName(content)[0]; // 対象の.js-acクラス内の開閉する要素
  const MAX_HEIGHT = CONTENT.scrollHeight; // 対象の.js-acクラス内の開閉する要素の高さ
  const DURATION = MAX_HEIGHT * speed; // 開閉スピード
  CONTENT.style.transitionDuration = `${DURATION}ms`; // transition-durationを設定
  CONTENT.style.transitionTimingFunction = cssEase; // transition-timing-functionを設定
  
  // ボタンがクリックされるたびに、開閉する要素の高さと開閉フラグをトグル
  BTN.addEventListener('click', () => {
    CONTENT.style.height = isShow ? 0 : `${MAX_HEIGHT}px`;
    isShow = !isShow;
  });
}
```

`scrollHeight()`メソットを使うと、**要素のもともとの高さを取得できる**ので、CSSで対象の要素を予め`height: 0;`にしておけば、CSS Transitionで開閉をスムーズにアニメーションさせることができます。

また、`const DURATION = MAX_HEIGHT * speed;`とすることにより、開閉する要素の高さが違っても、同じようなスピード感で開閉できるようにしています。

### 実行
```js:JavaScript
// 実行
accordion({
  // 初期値の上書き
  speed: 1, // 1で100px 100msのスピード
  cssEase: 'ease'
});

// 上書きなしで実行
// accordion();
```

実引数で、初期値を上書きすることができます。オブジェクト形式で書くので、見やすいです。

## コードペン
<p data-height="512" data-theme-id="0" data-slug-hash="rQyzZX" data-default-tab="js,result" data-user="boltkeep" data-pen-title="No jQuery Accordion" class="codepen">See the Pen <a href="https://codepen.io/boltkeep/pen/rQyzZX/">No jQuery Accordion</a> by Otsuka Yuhi (<a href="https://codepen.io/boltkeep">@boltkeep</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

以上！