はじめに
AmazonなどのECサイトで、商品に対して星をつけて商品の評価をしているのを、
見たことありませんか?
「この商品は5つ星!これは3つ星!」のような。
アラビア数字で「これは何点」と表記されているよりも、すごくすごくわかりやすいですよね。
背景
筆者はWebフレームワークの勉強の課題として、
「読んだ技術書を評価してリストアップする」Webアプリケーションを製作中なのですが、
データベースに登録した評価カラムの数字を取り出して、その内容を星の個数として反映することを目指しました。
注意
-
問題解決からしばらく経ってからの投稿なので、データベースの中身などに矛盾が発生しています。
(例えば、対応する技術書の評価の数がスクリーンショットごとに異なるとか。) -
上の例のような、星3.5個というような小数は想定していません。
あくまで星1, 2, 3, 4, 5個としての実装です。
開発環境
- Node.js 12.16.3
- Express 4.17.1
- MySQL 8.0.19
実装したいもの
- 星の数は常に5つ表示する
- 評価数に応じて星の色をオレンジにすることで、評価点を確認できるようにする
- 評価数に満たない部分は灰色の星として表示する
- これらによって、「評価点の最大値がいくらか」「この本の評価点がいくつか」の可読性を一気に向上させる
解決方法
まずヴァニラなHTML・CSSを用意する
まず、星を表示するソースコードを用意する必要があります。
こちらを参考にしました。
改変したところ:uncheckedというクラスも用意した(文字色をgreyに変更する)
ソースコード
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<span class="fa fa-star checked"></span>
<span class="fa fa-star checked"></span>
<span class="fa fa-star checked"></span>
<span class="fa fa-star unchecked"></span>
<span class="fa fa-star unchecked"></span>
.checked {
color: orange;
}
.unchecked {
color: grey;
}
表示結果
実装してみる
データベースの中身
このテーブルの"good"というカラムが評価(星の数)に対応します。
実装前のソースコードとスクリーンショット
app.get("/", (req, res) => {
const sql = "select * from book";
connection.query(sql, function (err, result, fields) {
if (err) throw err;
res.render("index", { book: result });
});
});
<table>
<tr>
<th>タイトル</th>
<th>著者</th>
<th>出版社</th>
<th>評価</th>
<th>更新</th>
<th>削除</th>
</tr>
<% book.forEach(function (value) { %>
<tr>
<td class="title"><%= value.title %></td>
<td><%= value.author %></td>
<td><%= value.publisher %></td>
<td><%= value.good %></td>
<td><a href="/edit/<%= value.title %>">更新</a></td>
<td>
<a
href="/delete/<%= value.title %>"
onClick="disp('<%= value.title %>'); return false;"
>削除</a
>
</td>
</tr>
<% }); %>
</table>
実装後のソースコードとスクリーンショット(そして補足コメント)
const maxStar = 5;
app.get("/", (req, res) => {
const sql = "select * from book";
connection.query(sql, function (err, result, fields) {
if (err) throw err;
books = [];
for (book of result) {
book.colored = book.good; // 評価の数(オレンジ色の星の数)
book.uncolored = maxStar - book.good; // 灰色の星の数
books.push(book);
}
res.render("index", { book: books });
});
});
<table>
<tr>
<th>タイトル</th>
<th>著者</th>
<th>出版社</th>
<th>評価</th>
<th>更新</th>
<th>削除</th>
</tr>
<% book.forEach(function (value) { %>
<tr>
<td class="title"><%= value.title %></td>
<td><%= value.author %></td>
<td><%= value.publisher %></td>
<td>
<% for (let i = 0; i < value.colored; i++){ %>
<span class="fa fa-star checked"></span>
<% } %> <% for (let i = 0; i < value.uncolored; i++){ %>
<span class="fa fa-star unchecked"></span>
<% } %>
</td>
<td><a href="/edit/<%= value.title %>">更新</a></td>
<td>
<a
href="/delete/<%= value.title %>"
onClick="disp('<%= value.title %>'); return false;"
>削除</a
>
</td>
</tr>
<% }); %>
</table>
app.jsについて
実装前では「評価の数」だけあればよかったのですが、
今回は「オレンジ色に染まった星の数」「色がついていない(ように見える灰色の)星の数」という2つの変数が必要になります。
データベースからレコードを取り出したあと、
評価数の最大値(5)から、goodカラムの数を引くことで、灰色の星の数を取得し、
それらをまとめて初期化した配列 books に挿入、index.ejsへレンダリングすることで解決を図っています。
index.ejsについて
ejsファイルは通常HTMLで用いるJavaScriptだけでなく、
app.jsから渡されたデータを利用したJavaScriptを埋め込むことができます。
星の数について使った部分は以下です。
colored変数に格納された数だけforループしオレンジ色の星を表示、
uncolored変数に格納された数だけforループし、灰色の星を表示させます。
<% for (let i = 0; i < value.colored; i++){ %>
<span class="fa fa-star checked"></span>
<% } %> <% for (let i = 0; i < value.uncolored; i++){ %>
<span class="fa fa-star unchecked"></span>
<% } %>