localStorageでちょっとしたデータを保存できる便利ツールを作ってみよう

# はじめに
本記事は、localStorageを使ってWebページ上で文字列を保存でき、Webページを閉じてもデータが消失せず再度読み込み可能な、簡単な便利ツールを制作します。

:::note info
本記事に添付のソースコードについては、個人的な利用の範疇で、自由に使用・改変いただいて構いません。
:::

# 目次
1. localStorageとは
2. localStorageへの読み書き
3. きっかけになった困りごと
4. 便利ツールを作ってみた
5. ソースコード

# localStorageとは
localStorageとは、ブラウザが提供するデータ保存の仕組みであり、Webページでデータをクライアント保存できます。最大の特徴はブラウザを閉じてもローカルでデータを保持できるということです。
サイズはブラウザ依存ですが5MB程度で、ブラウザやタブを閉じても永続的に保持されます。クライアント側にのみ保存され、サーバーには送信されません。
JavaScriptを用いて常にアクセス可能ですので、例えば他のページで保存したデータであっても無制限にアクセスが可能です。言い換えると、<b>機密情報は絶対に保存してはならないということです。</b>

:::note alert
他ページで保存したデータであっても無制限にアクセス可能であるため、<b>機密情報は保存してはいけません</b>。
:::

<table>
  <caption>WebStorage</caption>
  <thead>
    <tr>
      <th>名前</th> <th>説明</th>
    </tr>
  </thead>
  <tr>
    <td> sessionStorage </td> <td>ブラウザを開いている間だけ(セッション)データを保存</td>
  </tr>
  <tr>
    <td> <b>localStorage</b> </td> <td>ブラウザを閉じてもデータを保存(永続的)</td>
  </tr>
</table>

# localStorageへの読み書き
「キー」と「値」は必ずセットでないといけません。

<b>文字列を保存するとき</b>
``` JavaScript
localStorage.setItem("place", "東京都");
```
第1引数はキー(名前)、第2引数は保存する文字列となります。この場合であれば、キーがplaceで"東京都"という文字列が保存されます。

<b>文字列を読み込むとき</b>
``` JavaScript
tmp = localStorage.getItem("place");  
```
引数にキーを指定します。この場合だと、保存した"東京都"という文字列がtmpに格納されます。


# きっかけになった困りごと
自身が所属していた立命館大学びわこ・くさつキャンパスの駐輪場は大変広いです。駐輪場の番号はA1から多分E8くらいまであって、どこに停めたのか本当に分からなくなります。気になる方は、Googleマップで見てみてください。
https://maps.app.goo.gl/DQArRKw5E2qpDv1C6

そんなこんなで、駐輪場所をいつもスマホのメモに保存していたのですが、寒空の下かじかむ手でフリック入力するのは大変辛く、なんとか便利にできないだろうかと、レポートそっちのけで思案した結果、このツール(Webページ)を作ることになりました。

# 便利ツールを作ってみた
題して、<b>駐輪場所把握システム</b>です。たいそうな名前ですが、実際はlocalStorageを使ってブラウザに保存しているだけの簡単なものです。localStorageの読み書き方法は、前章で説明しているので、そちらを参照してくださいね。


![駐輪場所把握システム](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3952515/c369b29d-8577-8e2b-afe3-f2da94d9c068.png)

HTMLとCSSの簡単な知識があれば理解できると思います。（CSSの説明は割愛します。）
HTMLファイルの中に、CSSとJavaScriptを埋め込んでいます。HTML要素の編集は以下の例のようにして行います。
この場合だと、id名がpv-statusであるspanクラスの要素を"に駐輪しています"にしています。保存したときに、「〇〇に駐輪しています。」と表示するところの一部分ですね。

``` JavaScript
document.getElementById("pv-status").textContent = "に駐輪しています";
```

JavaScript上で定義したsave関数の呼び出しは、以下のようなボタンを作ることで実現しています。「駐輪場所保存」と書かれたボタンをクリックしたら、save関数が呼び出されるといった具合です。
``` html
<input type="button" onclick="save()" value="駐輪場所保存" class="wd1">
```

次章にソースコードを添付するので、みなさんもぜひ活用してくださいね。

# ソースコード
``` html
<!DOCTYPE html>
    <html lang="ja"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>駐輪場所把握システム</title>
    </head>

    <body>

        <!-- 駐輪場所を選択するプルダウン -->
        <section id="input">
            <select id="pos-alphabet">
                <option value="A">A</option>
                <option value="B">B</option>
                <option value="C">C</option>
                <option value="D">D</option>
                <option value="E">E</option>
                <option value="F">F</option>
            </select>

            <select id="pos-number">
                <option value="1">1</option>
                <option value="2">2</option>
                <option value="3">3</option>
                <option value="4">4</option>
                <option value="5">5</option>
                <option value="6">6</option>
                <option value="7">7</option>
                <option value="8">8</option>
            </select>
        </section>

        <!-- 駐輪場所保存・表示関連 -->
        <section id="save-confirm">
            <div>
                <input type="button" onclick="save()" value="駐輪場所保存" class="wd1">
            </div>
        
            <div id="place">
                <div id="save-success"></div>
                <span id="save-status"></span>
            </div>
        </section>

        <section id="preview">
            <div id="pv-cont">
                <div id="pv-time"></div>
                <div id="pv-place"></div>
                <span id="pv-status"></span>
            </div>
        </section>


        <div id="footer">
            <hr>
            (c)2024 nanbu1234 - ver 1.1(20241225Christmas)
        </div>

        <!-- JS -->
        <script>
            // 駐輪場所読み込み
            document.getElementById("pv-time").textContent = localStorage.getItem('date');
            document.getElementById("pv-place").textContent = localStorage.getItem('posa') + localStorage.getItem('posn');
            document.getElementById("pv-status").textContent = "に駐輪しています";

            
            function save(){
                const day = new Date();
                // 駐輪時刻保存
                const date = day.getFullYear()+"/"+ (day.getMonth()+1) + "/" + day.getDate() + " " + day.getHours() + ":"+ day.getMinutes().toString().padStart(2, '0') + ":"+ day.getSeconds().toString().padStart(2, '0');
                localStorage.setItem('date', date);

                // 駐輪位置保存
                const posa = document.getElementById("pos-alphabet").value;
                const posn = document.getElementById("pos-number").value;
                localStorage.setItem('posa', posa);
                localStorage.setItem('posn', posn);
                document.getElementById("save-status").textContent = "";
                document.getElementById("save-success").textContent = "保存完了！";

                // 駐輪場所読み込み
                document.getElementById("pv-time").textContent = localStorage.getItem('date');
                document.getElementById("pv-place").textContent = localStorage.getItem('posa') + localStorage.getItem('posn');
                document.getElementById("pv-status").textContent = "に駐輪しています";
            }
        </script>

        <!-- CSS -->
        <style>
            .wd1{
                font-size: 1.5rem;
                font-weight: bold;
                margin-left: 25%;
                margin-right: 25%;
                width: 50%;
                height: 3rem;
            }

            .wd2{
                margin-top: 2rem;
                font-weight: bold;
                margin-left: 35%;
                margin-right: 35%;
                width: 30%;
                height: 3rem;
            }
            
            
            select{
                font-size: 3rem;
            }

            #input{
                font-size: 2rem;
                text-align: center;
                margin-bottom: 1rem;
            }

            #place{
                text-align: center;
                margin-bottom: 2rem;
            }

            #save-success{
                margin-top: 2rem;
                font-size: 2rem;
                font-weight: bold;
            }

            #save-place{
                display: inline;
                background-color: black;
                font-size: 2rem;
                font-weight: bold;
                color: white;
            }

            #save-time{
                font-weight: bold;
                text-align: center;
            }

            #pv-cont{
                text-align: center;
                margin-bottom: 2rem;
            }

            #pv-title{
                margin-top: 2rem;
                text-align: center;
                font-size: 1.5rem;
                font-weight: bold;
            }

            #pv-time{
                text-align: center;
            }

            #pv-place{
                display: inline;
                margin-top: 0.5rem;
                background-color: black;
                font-size: 2rem;
                font-weight: bold;
                color: white;
                text-align: center;
            }

            #footer{
                margin-top: 3rem;
                text-align: center;
                font-size: 0.7rem;
            }
        </style>

    </body>
</html>
```