JavaScript 状態保存する折りたたみUI

# 参考にしたページ

折りたたみUIを検索したら、次のところみつけて実装できました。

[クリックすると展開表示する"折りたたみメニュー"をホームページに簡単に作る方法 | ふかふか交易所](http://fukafuka295.jp/hp/hp_no10.html)

また、保存先のlocalStorageについてはこちらを参考にしました。

[LocalStorageとは？ その使い方を徹底解説！](http://wp.tech-style.info/archives/742)

[WebStorage API(LocalStorage)を使ってみた - Qiita](https://qiita.com/masamitsu-konya/items/c69515604570150d3ab9)

保存先のCookieの使い方はこちらを参考にしました。

[【javascript入門】cookieの使い方まとめ | 侍エンジニア塾ブログ | プログラミング入門者向け学習情報サイト](https://www.sejuku.net/blog/28696)


# 状態保存機能を追加したい

たくさんの折りたたみ項目を作ってリンク管理してたのですが、

別ページにリンクしていき、戻ってきた場合に全項目が折りたたまれてしまっているのは残念でした。

なので、再表示したときも折りたたみメニュー項目が保存されているものを作ってみました。

# ソースコード localStorage版

次のようなコードになります。
あとで紹介するCookie版とは違い、ローカルファイルとして動かしても動作します。

```index.html
<!DOCTYPE html>
<html lang="ja"><head>
  <meta charset="utf-8">

<script>

  var openStatusDic = {};

  var openArea = function(id) {
    var obj = document.getElementById(id).style;

    obj.display = (obj.display === 'none') ? 'block' : 'none';

    openStatusDic[id] = (obj.display === 'block');
    localStorage.setItem('openStatusDic',
      JSON.stringify(openStatusDic));
  }

  document.addEventListener("DOMContentLoaded",function(event){

    //起動時に値があればタブ状態を戻す
    var itemValue = localStorage.getItem('openStatusDic');
    if (itemValue !== null) {
      openStatusDic = JSON.parse(itemValue);

      for (var prop in openStatusDic) {
        if (openStatusDic.hasOwnProperty(prop)) {
          if (openStatusDic[prop] === true) {
            openArea(prop);
          }
        }
      }
    };
  },false);

</script>

</head><body>

  <!-- 折りたたみみ部 -->
    <div onclick="openArea('open01');">
    <a style="cursor:pointer;">▼ クリックで展開</a>
    </div>
    <!--// 折り畳み展開ポインタ -->

    <!-- 折り畳まれ部分 -->
    <div id="open01" style="display:none;clear:both;">
    テスト1
    </div>
  <!-- 折りたたみ部終わり -->

  <!-- 折りたたみみ部 -->
    <div onclick="openArea('open02');">
    <a style="cursor:pointer;">▼ クリックで展開</a>
    </div>
    <!--// 折り畳み展開ポインタ -->

    <!-- 折り畳まれ部分 -->
    <div id="open02" style="display:none;clear:both;">
    テスト2
    </div>
  <!-- 折りたたみ部終わり -->

</body></html>
```

# ソースコード Cookie版

Cookieを使ったコードは、次のようなものになります。

コメント欄で指摘していただいたように、このような画面の状態保存のためにはCookieは古いし適切ではないので使わないほうがいいとのことでした。コードとしては残しておきます。

Cookieはサーバー通信が発生するためだと思われますが、ローカルファイルだとうまく動かないので、Webサーバー上で動作確認してください。

```index.html

<!DOCTYPE html>
<html lang="ja"><head>
  <meta charset="utf-8">

<script>

  const SEC_MILLISEC  = 1000;
  const MIN_MILLISEC  = 1000 * 60;
  const HOUR_MILLISEC = 1000 * 60 * 60;
  const DAY_MILLISEC  = 1000 * 60 * 60 * 24;

  var setCookie = function(name, value, expiresMillisec) {
    var d = new Date();
    d.setTime(d.getTime() + expiresMillisec);
    document.cookie = name + '=' + encodeURIComponent(value)
      + ';expires=' + d.toUTCString();
  };

  var getCookie = function(name) {
    if (document.cookie) {
      //cookieは[name=value; name=value; name=value; ]の形式
      var nameValues = document.cookie.split("; ");
      for (var i = 0, il = nameValues.length; i < il; i += 1) {
        var nameValue = nameValues[i].split("=");
        if (nameValue[0] === name) {
          return decodeURIComponent(nameValue[1]);
        }
      }
    }
    return '';
  };

  var openStatusDic = {};

  var openArea = function(id) {
    var obj = document.getElementById(id).style;

    obj.display = (obj.display === 'none') ? 'block' : 'none';

    openStatusDic[id] = (obj.display === 'block');
    setCookie('openStatusDic', JSON.stringify(openStatusDic), 30 * DAY_MILLISEC);
  }

  document.addEventListener("DOMContentLoaded",function(event){

    //起動時に値があればタブ状態を戻す
    var cookieValue = getCookie('openStatusDic');
    if (cookieValue !== '') {
      openStatusDic = JSON.parse(cookieValue);

      for (var prop in openStatusDic) {
        if (openStatusDic.hasOwnProperty(prop)) {
          if (openStatusDic[prop] === true) {
            openArea(prop);
          }
        }
      }
    };

  },false);

</script>

</head><body>

  <!-- 折りたたみみ部 -->
    <div onclick="openArea('open01');">
    <a style="cursor:pointer;">▼ クリックで展開</a>
    </div>
    <!--// 折り畳み展開ポインタ -->

    <!-- 折り畳まれ部分 -->
    <div id="open01" style="display:none;clear:both;">
    テスト1
    </div>
  <!-- 折りたたみ部終わり -->

  <!-- 折りたたみみ部 -->
    <div onclick="openArea('open02');">
    <a style="cursor:pointer;">▼ クリックで展開</a>
    </div>
    <!--// 折り畳み展開ポインタ -->

    <!-- 折り畳まれ部分 -->
    <div id="open02" style="display:none;clear:both;">
    テスト2
    </div>
  <!-- 折りたたみ部終わり -->

</body></html>

```

# ソース説明

どちらのソースもほとんど中身は変わりません。

openStatusDic は、連想配列的な Dictionary としてオブジェクトを使い、
openAreaで、領域の開いたり閉じたりをしていて、
その際に、openStatusDicに状態を記録していて、
それを、JSONとしてlocalStorage、もしくは、Cookieにセットしています。

setCookie / getCookie は、汎用関数です。

起動時には
DOMContentLoaded イベントで、JSONからオブジェクトを戻し、openStatusDicの内容にしたがって、折りたたみ状態を復帰させています。

localStorageやCookieの使い方などのご参考にどうぞです。