はじめに
前回の記事【Vue+TypeScriptで作る『レスポンシブでスクローラブルなリスト』】
では、メンバをリスト表示してフィルタやソートをできるようにしましたが、リストは味気ないままでした。今回はこのときのリストを1行ごとに背景色を変え、選択行も一目で分かる様に、条件付きStyle を使って見た目をよくしたいと思います。まずは「出来上がりはこんな感じ」を確認して始めましょう。
出来上がりはこんな感じ
コードはここです。
GitHub - Shikataramuno/responsive-scrollable-grid at ver1.1
リストの行の背景色が交互に変わっています。それと選択されている行の背景色がそれらとは違う背景色になっていて被選択行がどれか一目で分かる様になって、UX的もGood!👍ですね。
背景色の変え方
行の背景色はCSSで設定しますが、それだけではユーザーの操作に反応してダイナミックに変化させることはできません。ではどうやってやるのでしょうか?htmlで行を表す要素にインラインスタイルをバインドして指定しておき、条件式でスタイルオブジェクトを切り替える様にします。詳しくは公式ドキュメントを参照してください。
変更内容
それでは具体的な実装を見ていきましょう。前回からの修正部分について解説していきます。
今回修正を加えるのは ResponsiveScrollabelGridコンポーネントだけです。
行ごとの背景色
まずは、行ごとに背景色を切り替えるので、まずは奇数行と偶数行に指定するスタイルオブジェクトを定義します。 スタイルオブジェクトはクラスのプロパティ変数にbackgroundのCSSプロパティをキーとしたjsonオブジェクトとして定義します。 こんな感じです。
・・・・・中略 @Component export default class ResponsiveScrollableGrid extends Vue { ・・・・・中略 styleForNonSelectedEvenRow: object = {'background-color': '#FFFFFF'}; styleForNonSelectedOddRow: object = {'background-color': '#F5F5F5'}; ・・・・・中略
次にこのスタイルをhtmlの要素にバインドします。 インラインスタイルを指定するhtmlの要素は行ごとの繰り返し構造にあたる以下の部分になります。
// 49: <div class="data-field"> <div v-for="(entry,idx) in members" v-bind:key=idx"> <div class="table-row data"> <div class="wrapper attributes data"> <div v-for="(val, idx) in columns" v-bind:key=idx :class="[val]"> <span class='mobile-title'>{{val}}:</span> <span> {{entry[val]}} </span> </div> </div> </div> </div> </div>
1行に該当する要素は51~61行目になります。1行丸ごと背景色を指定するのでスタイルは51行目の div 要素に指定します。
htmlの要素奇数行と偶数行のどちらかを判断し条件に加えます。リストの何行目かは50行目の idx で分かるので、よくある2の剰余を条件式として使います。
条件付きスタイルを適用するとこんな感じになります。
// 49: <div class="data-field"> <div v-for="(entry,idx) in members" v-bind:key=idx"> <div class="table-row data" v-bind:style="[idx%2 === 0 ? styleForNonSelectedEvenRow : styleForNonSelectedOddRow]"> <div class="wrapper attributes data"> <div v-for="(val, idx) in columns" v-bind:key=idx :class="[val]"> <span class='mobile-title'>{{val}}:</span> <span> {{entry[val]}} </span> </div> </div> </div> </div> </div>
これで、行ごとの背景色が変わりました。次はこれに加えて選択行の背景色を変えます。
選択行の背景色
まず、選択行を識別するために行のクリックイベントで選択行を保持するイベントハンドラを定義します。
// 49: <div class="data-field"> <div v-for="(entry,idx) in members" v-bind:key=idx> <div class="table-row data" v-bind:style="[idx%2 === 0 ? styleForNonSelectedEvenRow : styleForNonSelectedOddRow]" @click="edit(entry.id)"> <div class="wrapper attributes data"> <div v-for="(val, idx) in columns" v-bind:key=idx :class="[val]"> <span class='mobile-title'>{{val}}:</span> <span> {{entry[val]}} </span> </div> </div> </div> </div> </div>
1行の要素にあたる51行目 div 要素に @click="edit(entry.id)" を追加し、被選択メンバ(entry)の id を引数としてクラスメソッドの edit を呼び出す様にします。
そして、クラスメソッド edit で id をクラスのプロパティ変数にセットします。
実装はこんな感じです。
・・・・・中略 @Component export default class ResponsiveScrollableGrid extends Vue { ・・・・・中略 selectedId: number = -1; // 被選択メンバのidを保持するプロパティ変数を定義(-1は未選択を意味する初期値) ・・・・・中略 edit(id: number): void { // クリックイベントで呼び出されるメソッド this.selectedId = id; } } ・・・・・中略
最後に条件付きスタイルに選択行であるか否かの判断を付け加え、スタイルを切り替えます。 上述の行ごとの切替と同じく、選択行のスタイルを表すスタイルオブジェクトをクラスのプロパティ変数に追加します。
・・・・・中略 @Component export default class ResponsiveScrollableGrid extends Vue { ・・・・・中略 styleForSelectedRow: object = {'background-color': '#C0C0C0'}; ・・・・・中略
そして、行ごとの条件式に選択行の条件を加えます。
<div class="table-row data" v-bind:style="[selectedId===entry.id ? styleForSelectedRow : idx%2 === 0 ? styleForNonSelectedEvenRow : styleForNonSelectedOddRow]" @click="edit(entry.id)">
三項演算式が重なるので多少わかりずらいかもしれませんが、選択行であるか否かを判断し、選択行でなければ奇数、偶数を判断するという順序になります。 これで、修正は完了です。
出来上がり!
さぁビルドしてみましょう。
>npm run serve
正常に終了したらlocalhost:8080にアクセスしてみてください。エラーがなければ出来上がりはこんな感じと同じUIが表示されるはずです。 これで行の区別とどの行が選択されているか、はっきりわかるようになってUX的にもよくなりました。
まとめ
最後まで読んでいただきありがとうございます。
今回は条件付きスタイルの使い方を具体的に解説してみました。少しでもお役に立てれば幸いです。