つくる ギャラリーをデータ駆動にする
このレッスンで分かること
- 同じ一覧を HTML と配列の両方が持っていると、直す場所が決まらなくなります
- 描き直す関数は、まず中身を空にしてから描くと、何度呼んでも結果が同じになります
作品を 1 つ足したいとき、どちらに書けばいいのか
いま作品の一覧には 5 枚のカードが並んでいます。ところが出どころは 2 か所に分かれています。HTML に直接書いた article が 3 枚、配列から JavaScript が描いたものが 2 枚です。
ここで作品を 1 つ増やしたくなったとき、どちらに足せばいいのでしょうか。どちらでも出せてしまいます。だから半年後の自分は迷いますし、並び順を変えたくなったときには HTML と JavaScript を見比べる必要が出ます。これが二重管理です。
答えは単純で、片方に寄せます。寄せる先は配列のほうです。データにしておけば、並べかえも絞り込みも、あとから来る機能を全部その 1 か所で受け止められます。
寄せる手順は 2 つに分けてください。いきなり HTML の 3 枚を消すと、うまくいかなかったときに何が原因なのか分からなくなります。
- まず配列に 3 枚ぶんのデータを足し、JavaScript が描いたカードが HTML の 3 枚と同じ見た目になることを確かめる
- 見た目がそろってから、HTML の
article3 つと、それを掴んでいた古いコードを消す
1 の途中では、同じ作品のカードが 2 枚ずつ並びます。それでいいのです。並んでいる状態で、文字の入り方や枠の付き方をよく見比べます。ここで違いに気づいておけば、消したあとに慌てずに済みます。
動いているものを置きかえるときは、いつでもこの順番が安全です。新しいほうを先につくり、両方が同じ結果になることを見てから古いほうを外す。実務では並行稼働と呼ばれるやり方で、Web に限らずデータの移行でも使われます。
2 回呼ぶと、カードが倍になる
前回書いた forEach は、そのままでは 1 回しか使えません。append は足すだけで、前にあったものを消さないからです。同じ関数をもう一度呼べば、同じカードがもう一組ぶら下がります。
そこで、描き直す関数の 1 行目で中身を空にします。
JavaScript
const list = document.querySelector(".hobby-list");
list.textContent = ""; // 先に空にしてから描き始めるtextContent に空文字を入れると、子要素はまるごと消えます。第3章で「代入すると中身が消える」と話したあの性質を、ここでは消すために使います。
この 1 行があると、何度呼んでも結果が同じになります。HTML に書いてあった 3 枚も、この行で消えます。つまり消し忘れても画面は正しくなります。それでも HTML からは消してください。読む人が「この 3 枚はどこに出ているのだろう」と探すことになるからです。
「1 枚目を強調する」と書くのをやめる
class を付け外しした回では、手で 1 枚目に featured を付けました。並び順が変われば、強調される作品も変わってしまう書き方です。せっかくデータを持っているので、値のほうに判断させます。
JavaScript
if (hobby.times >= 10) {
item.classList.add("pinned");
}つくる関数の中にこうした 3 行を置くだけで、条件に合うものだけが自動で目立ちます。前は「1 枚目を強調する」と書いていました。いまは「よく見られているものを強調する」と書いてあります。データが変われば、強調される相手も勝手に変わります。第4章の条件分岐が、画面の見え方を決める道具になりました。
完成すると、works の 1 行を書きかえるだけで画面がそのとおりに変わります。作品を足せばカードが増え、published を false にすれば消える。DOM を組み立てるコードには一切さわりません。これが、この章の到達点です。
よくある間違い
- 空にせずに描いて、カードが倍になる — 描き直す関数の 1 行目を空にする、と決めてしまうのがいちばん確実です
- HTML の見た目と、JS でつくる見た目がずれる — 原因の大半は class の付け忘れです。HTML では
<article class="work-card">なのに、classNameを書き忘れると枠も余白も付かない裸のarticleが並びます - 消したはずの要素を掴んだままにする — HTML から要素を消すと、それを掴んでいた古いコードが
undefinedを触りにいきます
JavaScript
const items = document.querySelectorAll(".hobby-item"); // 空になった
items[0].classList.add("pinned"); // TypeError で止まるTypeError で止まれば、その下の処理も全部動きません。使わなくなったコードを消すのは、読みやすさのためだけではないのです。
課題
worksに 6 件のオブジェクトを入れる。HTML に書いてあった 3 枚もデータとして入れ、「つくりかけの計算機」だけpublishedをfalseにするcreateWorkCard(work)の中で、work.viewsが 100 以上ならclassList.add("featured")を付けるrenderWorks(list)を書く。最初に.work-listをtextContent = ""で空にしてから、公開ぶんだけをappendするcardsを使っていた第58回から第60回の処理を消し、HTML パネルのarticle.work-card3 つも消す