【JavaScript入門】ストレージを利用する(storage.js)

 ここでは「みんなのつぶやき」アプリで 編集中の画像 (Canvas) とコメント自動で保存/復元 できるようにするユーティリティ storage.js を実装します。
 ブラウザの localStorage をラッパー関数で包み、「いつ」「誰が」呼び出しても安全に扱えるよう設計するのがポイントです。

フォルダ構成

まずはフォルダ構成を再確認しておきます。

node-js/
 ├─ app/
 │   ├─ index.html
 │   ├─ style.css
 │   └─ js/               ← JS モジュール群
 │        ├─ common.js
 │        ├─ storage.js   ← ここで作成
 │        ├─ imageArea.js
 │        ├─ imageEffects.js
 │        ├─ controlArea.js
 │        ├─ commentArea.js
 │        ├─ sendArea.js
 │        ├─ dateFormat.js
 │        └─ postListArea.js
 ├─ index.js               ← API/サーバ側
 ├─ upload_images/         ← 画像保存場所
 └─ post-dat.txt           ← 投稿データ(JSON など)

1.なぜ localStorage なのか

ストレージ破棄タイミング容量 (目安)今回の適合度
sessionStorageタブ/ウィンドウを閉じると消える。5 MB 程度 アプリ再訪で復帰できない
localStorage明示的に削除しないか、ブラウザ設定で消すまで残る。5 MB 程度 編集途中を永続化できる

2.コメント付き storage.js

/* ---------------------------------------------------
   storage.js
   画像 (Canvas) と コメント を localStorage に保存・復元
   - 依存ライブラリなし
   - すべての公開 API を window.* にぶら下げ、他 JS から容易に呼べる
--------------------------------------------------- */

// ページ表示直後に “前回の作業状態” を復元
window.addEventListener('DOMContentLoaded', () => {
  restoreCanvasFromStorage();
  restoreCommentFromStorage();
});

/* ========= 定数(ストレージキー) =========== */
const KEY_CANVAS  = 'appCanvas';   // Base64 化した画像データ
const KEY_COMMENT = 'appComment';  // テキストエリアの内容

/* ========= Canvas の保存 =========== */
/**
 * <canvas id="view"> を PNG(Base64) で localStorage へ保存
 * 5MB 制限を超えると例外が出るので大きい画像は要注意
 */
function saveCanvasToStorage(){
  const canvas  = document.querySelector('#view');
  const dataURL = canvas.toDataURL();     // "data:image/png;base64,..." 形式
  localStorage.setItem(KEY_CANVAS, dataURL);
}

/**
 * 起動時に保存済み Canvas があれば復元
 */
function restoreCanvasFromStorage(){
  const dataURL = localStorage.getItem(KEY_CANVAS);
  if (!dataURL) return;                   // そもそも未保存なら何もしない

  const canvas = document.querySelector('#view');
  const ctx    = canvas.getContext('2d');
  const img    = new Image();

  // Base64 → Image → Canvas へ描画
  img.onload = () => {
    ctx.drawImage(img, 0, 0);
    canvas.setAttribute('time', Date.now());            // “いつ復元したか” のメモ
    document.querySelector('#noView').style.display='none';
    canvas.style.display = 'block';
  };
  img.src = dataURL;
}

/** Canvas データをストレージから削除 */
function removeCanvasStorage(){
  localStorage.removeItem(KEY_CANVAS);
}

/* ========= コメントの保存 =========== */
function saveCommentToStorage(){
  const txt = document.querySelector('#comment').value;
  localStorage.setItem(KEY_COMMENT, txt);
}

/**
 * デフォルト値は <textarea data-default="..."> で埋め込む
 */
function restoreCommentFromStorage(){
  const el  = document.querySelector('#comment');
  const val = localStorage.getItem(KEY_COMMENT) ?? el.dataset.default;
  el.value  = val;
}

/** コメントだけを削除 */
function removeCommentStorage(){
  localStorage.removeItem(KEY_COMMENT);
}

/* ========= パブリック API (グローバル公開) =========== */
window.saveCanvasToStorage   = saveCanvasToStorage;
window.removeCanvasStorage   = removeCanvasStorage;
window.saveCommentToStorage  = saveCommentToStorage;
window.removeCommentStorage  = removeCommentStorage;

3.主要命令サマリー

API / メソッド役割コツ & 使い所
localStorage.setItem(key, value)キーに文字列を保存必ず文字列。画像は canvas.toDataURL() で文字列化
localStorage.getItem(key)値を取得。存在しないと null?? 演算子でデフォルト値を用意
localStorage.removeItem(key)単独キーを削除ゴミ掃除/ログアウト時に
canvas.toDataURL()Canvas を PNG Base64 に直変換圧縮率はブラウザ実装依存
Image() → drawImage()Base64 文字列を再描画復元処理のお決まりパターン
window.addEventListener('DOMContentLoaded', cb)初期化フックページロード後ただちに復元

4.各関数の詳解

関数詳細
saveCanvasToStorage()#view の Canvas を Base64 PNG として保存。1 回の投稿ごとに呼ぶ想定。
restoreCanvasFromStorage()起動直後に呼ばれ、Base64 → <img>drawImage() の流れで表示を復元。#noView を非表示にし、ユーザに「画像が残っている」ことを示す。
removeCanvasStorage()画像をクリアしたあとローカルキャッシュも削除。エフェクト「削除」ボタンから呼ぶ。
saveCommentToStorage()textarea#comment の内容を保存。入力イベント keyup などから呼ぶとライブ保存が可能。
restoreCommentFromStorage()ローカルに値が無ければ data-default 属性を初期値として利用。
removeCommentStorage()投稿が完了したら呼び、次回は空のコメントでスタートさせる。

5.よくある疑問 Q&A

QA
容量 5 MB を超えたら?QuotaExceededError が発生。Base64 は 33% 程度肥大化するので、大画像はサーバ側にアップロードして URL だけ保存する設計も検討を。
複数タブで競合しない?同じオリジン&キーを奪い合うため競合の可能性あり。必要なら storage イベントで他タブと同期する実装を追加。
セキュリティは?localStorage は ドメイン+プロトコル 単位で隔離されるが、XSS があると盗まれる。ユーザ入力を HTML に挿入する際は必ずエスケープすること。

まとめ

 storage.js で実装した 5 つの公開関数(save / restore / remove × 画像・コメント) を使えば、他モジュールは「保存したいタイミングで呼ぶ」だけ。
 煩雑な Base64 変換や例外処理をファイル内に隠蔽したことで、アプリの可読性・保守性が大きく向上しました。

 次回は「ドラッグ&ドロップとファイルの読み込み (imageArea.js)」を徹底解説し、ユーザが画像をクリック/投下した瞬間から Canvas 描画までの流れを追っていきます。