つくる ひとことメモウィジェット

このレッスンで分かること

  • 配列に貯めたデータを画面に描き、追加と削除で貯め方を変える形が書けます
  • 描き直す関数を 1 本に決めておくと、追加も削除も同じ道を通ります
  • 変わったところで保存し、読み込み時に読み戻すと、メモがリロードをまたいで残ります

つくる ひとことメモウィジェット とは

この章までの全部を 1 か所に集める総合制作です。入力して追加、一覧に表示、削除ボタンで消す、そして保存。プロフィールサイトに小さなメモ帳を足します。

どの章の何を使うか

このレッスンは新しい文法をほとんど足しません。代わりに、ここまで別々に練習してきたものを 1 つの機能に合流させます。手が止まったら、下の表から該当する章に戻ってください。

使うものメモ帳のどこで効くか
第5章配列と push と spliceメモを貯める入れ物と、足す・抜く操作
第6章関数とコールバック描き直す関数、追加する関数、forEach に渡す関数
第7章オブジェクト1 件のメモを { text: "..." } の形で持つ
第8章createElement と appendChildli と span と button を組み立てて一覧に置く
第9章addEventListener と input の値追加ボタンと削除ボタン、入力欄の読み取り
第10章localStorage と JSONメモの配列を文字列にして保存し、読み戻す

いちばん大事な考え方は、画面ではなく配列を本物として扱うことです。追加も削除も、まず配列を書き換え、そのあと配列の中身をもとに一覧をまるごと描き直します。画面の側を直接いじって帳尻を合わせようとすると、件数の表示や削除ボタンの番号がすぐにずれます。

データを本物として持ち、画面はそれを写したものにする。この考え方はデータ駆動と呼ばれ、React のようなライブラリの土台にもなっています。入門の最後にこの形を手で書いておくと、次に進んだときの理解がまるで変わります。

描き直す関数を 1 本に決める

まず、いまの配列から一覧を作り直す renderMemos を書きます。最初に textContent を空にして中身を捨て、forEach で 1 件ずつ組み立て直します。

function renderMemos() { memoList.textContent = ""; memos.forEach(function (memo, index) { const item = document.createElement("li"); item.className = "memo-item"; const text = document.createElement("span"); text.className = "memo-text"; text.textContent = memo.text; const removeButton = document.createElement("button"); removeButton.className = "memo-delete"; removeButton.type = "button"; removeButton.textContent = "削除"; removeButton.addEventListener("click", function () { memos.splice(index, 1); saveMemos(); renderMemos(); }); item.appendChild(text); item.appendChild(removeButton); memoList.appendChild(item); }); memoCount.textContent = memos.length + " 件"; }

forEach の第 2 引数 index が、そのメモが配列の何番目かです。削除ボタンの中でその番号を使い、splice(index, 1) で 1 件だけ抜きます。関数の中から外側の index を見られるのは、第6章でやった通り、関数が書かれた場所の変数を覚えているからです。

削除したあとに renderMemos() をもう一度呼んでいるのを見落とさないでください。描き直すと番号は振り直され、残ったメモのボタンは正しい番号を持ち直します。1 件ずつ画面から要素を取り除く書き方にすると、この番号がずれて、2 件目を消したつもりが 3 件目が消える、という不具合になります。

追加する側

追加は、空のときを先に弾いてから配列に足します。第6章の早期 return です。

function addMemo() { const value = memoInput.value.trim(); if (value === "") { memoMessage.className = "form-message error"; memoMessage.textContent = "メモを入力してください"; return; } memos.push({ text: value }); saveMemos(); memoInput.value = ""; memoMessage.textContent = ""; renderMemos(); }

trim() は前後の空白を落とすメソッドです。これが無いと、スペースだけのメモが作れてしまいます。追加できたら memoInput.value を空にして、次のメモをすぐ打てるようにします。細かいですが、これがあるかないかで使い心地がはっきり変わります。

保存を挟む

保存は前のレッスンと同じ形です。配列はそのままでは入らないので JSON.stringify を通し、読むときに JSON.parse で戻します。読めなかったときは空の配列にしておけば、以降の処理は「まだ 1 件も無い」ときと同じに書けます。

function loadMemos() { try { const saved = localStorage.getItem("memos"); if (saved === null) return []; const parsed = JSON.parse(saved); return Array.isArray(parsed) ? parsed : []; } catch (error) { return []; } } function saveMemos() { try { localStorage.setItem("memos", JSON.stringify(memos)); } catch (error) { console.log("この環境では保存できません"); } } const memos = loadMemos();

Array.isArray で確かめているのは、保存された文字列が壊れていたり、別の形が入っていたときの用心です。memosconst で受けているのは、中身を pushsplice で変えることはあっても、入れ物そのものを別の配列に取り替えないからです。第7章でやった const と参照の話がそのまま当てはまります。

呼ぶ順番は、読み出してから描く、です。const memos = loadMemos(); を先に置き、最後に renderMemos(); を 1 回呼べば、前回のメモが並んだ状態でページが始まります。

よくある間違い

保存を書き忘れる場所があるという間違いが最も多いです。追加のときだけ保存して削除で忘れると、消したはずのメモがリロードで復活します。

// 間違い 配列は変わったのに保存していない memos.splice(index, 1); renderMemos(); // 正しい 変えたら保存する memos.splice(index, 1); saveMemos(); renderMemos();

描き直す前に中身を空にし忘れるのも定番です。

// 間違い 呼ぶたびに古い一覧の下へ足されていく function renderMemos() { memos.forEach(function (memo) { /* 追加していく */ }); } // 正しい まっさらにしてから組み立てる function renderMemos() { memoList.textContent = ""; memos.forEach(function (memo) { /* 追加していく */ }); }

splice(index) と第 2 引数を省くのも危ないです。この書き方だと、その位置から後ろが全部消えます。1 件だけ抜きたいときは splice(index, 1) と必ず 2 つ書いてください。

課題

  1. 作品とお問い合わせのあいだにメモの section を足す。入力欄 memo-input、追加ボタン memo-add、案内文 memo-message、一覧 memo-list、件数 memo-count を id で用意する
  2. メモの配列を持ち、loadMemos で localStorage から読み戻す。読めないときや保存が無いときは空の配列にする
  3. renderMemos 関数で一覧を作り直す。1 件ごとに li と削除ボタンを作り、memo-count に件数を入れる。削除ボタンは splice で 1 件だけ抜く
  4. 追加ボタンを押したら入力欄の値を trim して配列に足し、入力欄を空にして描き直す。空のときは追加せず memo-message に入力をうながす文を出す
  5. 追加と削除のどちらでも、配列を変えたあとに JSON.stringify で保存する

ヒント

index.html
style.css
script.js
プレビュー

できているか

  • 入力欄 #memo-input がある
  • 一覧 #memo-list がある
  • 空のまま追加すると案内が出る
  • 入力して追加すると一覧に 1 件出る
  • もう 1 件追加すると 2 件になる
  • 削除ボタンを押すと 1 件目だけ消える
  • 残りも消すと 0 件になる