自由拡張
このレッスンで分かること
- 欲しい機能を、使える文法の組み合わせに分解して設計できます
- 元の配列は残したまま、条件に合うものだけを取り出して描き直せます
- 状態を持つ変数を 1 つ決めると、切り替えの実装がすっきりします
自由拡張 とは
最後は自分で決めて足す回です。3 つの案から 1 つ選んで、プロフィールサイトに機能を 1 つ増やします。作るものを自分で決める練習でもあります。
3 つの案から 1 つ選ぶ
何を作ってもいい、と言われると手が止まります。なので案を 3 つ出します。どれも、ここまでに学んだ範囲だけで作れます。使う知識も並べたので、自分がいちばん復習したい章のものを選んでください。
| 案 | 作るもの | 主に使う章 |
|---|---|---|
| A 作品の絞り込み | 人気の作品だけを表示するボタン | 第5章 配列 / 第8章 DOM |
| B メモの検索 | 入力した文字を含むメモだけ表示する | 第6章 関数 / 第9章 入力欄 |
| C 訪問回数カウンター | 何回目の訪問かをヘッダーに出す | 第2章 型変換 / 第10章 保存 |
案 A は、作品の配列から views が一定以上のものだけを取り出して描き直します。配列を回して条件で選ぶ練習になります。案 B は、入力欄の input イベントに合わせてメモの一覧を絞ります。打つたびに描き直すので、第9章のイベントと第8章の描画が組み合わさります。案 C は localStorage に数値を貯めます。保存できるのは文字列だけなので Number(...) で戻す型変換が要ります。
このレッスンの合格条件は案 A で決めてあります。まず案 A を仕上げて条件を通し、余力があれば B や C も足してください。合格条件は最低ラインで、上限ではありません。
自分で決めて作ったものは、ポートフォリオで話せる材料になります。面接や相談の場で強いのは「言われた通りに作った」ではなく「こうしたかったからこう作った」です。小さくてかまわないので、選んだ理由を自分の言葉で説明できる状態にしておきましょう。
作る前に 3 行だけ書き出す
いきなりコードを書き始めると、たいてい途中で迷います。手を動かす前に、3 行だけ紙かコメントに書き出してください。
1 行目は、何が見えるようになるか。案 A なら「作品の上にボタンが 1 つあり、押すと人気の作品だけが並ぶ」です。2 行目は、そのために画面に足す要素の id か class。ここでは #works-filter のボタンと #works-count の件数表示です。3 行目は、覚えておく必要のある状態。案 A なら「いま絞り込んでいるかどうか」の 1 つだけです。
この 3 行がそろえば、あとは埋めるだけになります。要素は HTML に足す、状態は変数にする、押されたときの処理は addEventListener に書く。作りたいものを、使える文法の組み合わせに翻訳する作業がプログラミングの半分です。
// 見えるもの 作品の上にボタン 1 つと件数表示
// 足す要素 #works-filter と #works-count
// 覚える状態 popularOnly が true か false か描く関数は第8章のものをそのまま使う
うれしいことに、今回のために新しく作る描画処理はありません。第8章で renderWorks という関数を書いてあります。引数で受け取った配列を描き、最初の行で textContent を空にして描き直す形です。絞り込みに必要な性質は、そのときにもう満たしてあります。
// 第8章で書いた関数。引数の配列を描き、先に中身を空にしている
function renderWorks(list) {
const workList = document.querySelector(".work-list");
workList.textContent = "";
list.forEach((work) => {
if (!work.published) {
return;
}
workList.append(createWorkCard(work));
});
}あのとき renderWorks(works) と、引数で配列を受け取る形にしておいたのが効いてきます。works を関数の中で直接見に行く書き方にしていたら、絞り込んだ配列を渡せず、ここで書き直す羽目になっていました。今回やるのは、渡す配列を差し替えることだけです。
元の配列は壊さない
絞り込みでいちばんやってはいけないのが、元の works 配列そのものから要素を消してしまうことです。一度消したら元に戻せず、「すべて表示」に戻すすべがなくなります。元の配列はそのままにして、条件に合うものを別の配列に集めます。
function pickWorks() {
const picked = [];
for (const work of works) {
if (!work.published) continue;
if (popularOnly && work.views < 100) continue;
picked.push(work);
}
return picked;
}新しい空の配列を用意し、第5章の for-of で 1 件ずつ見て、条件に合わないものは continue で飛ばし、残ったものだけ push する。この形は覚えておく価値があります。条件を足していけば、今年のものだけ、名前に特定の文字を含むものだけ、と何にでも応用できます。
published が false のものを外しているのは、件数の表示と実際に並ぶカードの枚数をそろえるためです。renderWorks の側でも非公開は飛ばしているので、ここで外しておかないと「6 件を表示中」と出ているのにカードが 5 枚、というずれが起きます。
実は JavaScript には、この処理を 1 行で書く
filterというメソッドがあります。入門では扱いませんが、実践JavaScriptコースでmapやreduceと一緒に出てきます。いまfor-ofで手書きしておくと、filterを見たときに「ああ、あの処理か」とすぐつながります。
状態を 1 つの変数で持つ
いま絞り込んでいるのか、全部見せているのか。この「いまどっちか」を状態と呼びます。状態は真偽値の変数 1 つで持つのがいちばん素直です。
let popularOnly = false;
function updateWorks() {
const list = pickWorks();
renderWorks(list);
worksCount.textContent = list.length + " 件を表示中";
filterButton.textContent = popularOnly ? "すべての作品を見る" : "人気の作品だけ見る";
}
updateWorks();
filterButton.addEventListener("click", function () {
popularOnly = !popularOnly;
updateWorks();
});押されたら popularOnly をひっくり返し、あとは updateWorks に任せます。描き直し、件数の表示、ボタンの文字。画面に関わることを全部この関数に集めておくと、状態と画面がずれません。第9章のダークモードで applyTheme を 1 本にしたのと同じ設計です。
!popularOnly は第3章の否定です。true なら false、false なら true になります。popularOnly = !popularOnly の 1 行で切り替えが書けます。
ボタンの文字を状態に合わせて変えているのも大事な仕上げです。押したあとにボタンが「人気の作品だけ見る」のままだと、いまどちらの状態なのか使う人には分かりません。三項演算子で文字を出し分けるだけで、迷いが消えます。
案 B と案 C の進め方
案 B に進むなら、検索欄を 1 つ足して input イベントを聞きます。打たれた文字を memoInput のときと同じように読み、memo.text.includes(検索文字) が true のメモだけを集めて描き直します。includes は第7章で使った、含むかどうかを返すメソッドです。検索欄が空のときは全部見せる、という分岐を忘れないでください。
案 C なら localStorage に回数を貯めます。読み出した文字列を Number(...) で数値に戻し、1 を足して書き戻します。保存されていない初回は null が返るので、Number(null) が 0 になることを利用するか、?? "0" で既定値を用意します。前のレッスンと同じく try で囲むのを忘れずに。
よくある間違い
元の配列を書き換えてしまう間違いが最も多いです。
// 間違い works から消えてしまい、二度と戻せない
works.splice(1, 2);
renderWorks(works);
// 正しい 別の配列に集めて、描くときだけ差し替える
const picked = [];
for (const work of works) {
if (work.views >= 100) picked.push(work);
}
renderWorks(picked);状態を変えたのに描き直しを呼び忘れる、というのも定番です。変数だけ変わって画面が黙っているので、動いていないように見えます。
// 間違い 変数は変わったが画面はそのまま
filterButton.addEventListener("click", function () {
popularOnly = !popularOnly;
});
// 正しい 変えたら描き直す
filterButton.addEventListener("click", function () {
popularOnly = !popularOnly;
updateWorks();
});件数の表示を手で書き換えてしまうのも避けてください。worksCount.textContent = "1 件を表示中" のように直接書くと、条件を変えたときに必ずずれます。表示する配列の length から作れば、ずれようがありません。
課題
- 作品セクションに、絞り込みボタン works-filter と件数表示 works-count を id で足す
- 描き直しは第8章で作った renderWorks をそのまま使う。新しく作らず、渡す配列だけを変える
- いま絞り込んでいるかどうかを真偽値の変数 1 つで持つ
- 元の works 配列は書き換えず、published が true でかつ views が 100 以上のものだけを別の配列に集めて描く
- 描き直しと件数の表示とボタンの文字の更新を 1 つの関数にまとめ、読み込み時と押されたときの両方から呼ぶ