どうも、くずきです。
React
でテーブルをソートしようとした際に、View
自体のソートはあるんですが
サーバーと連動したやつがなかったので実装してみました。
やりたいこと
上記の画像はすでに完成品だけど、
∧
と∨
の部分のようなソートボタンを作る- ソート中のカラムはどれなのか色をつける
- ソートが降順か昇順かわかるようにする
- ソートした際URLが変わるようにする。
が、できれば問題ない。
ソートした場合にデータ取りに行く必要はあるんだけど、以前紹介したURL
が変更された際にリソースと再取得するという処理を親のコンポーネントに仕込んでいるので、URL
さえ変更すればいい。
コンポーネントの準備
まずは、テーブル用のコンポーネントの準備。
色々省略して、render
部分あたりのみ。
render() { return( <table> <thead> <tr> <th className="prof-image"></th> <th className="name"> <p className="text-left"> <Link to={TableUtil.getSortUrl("name")} //このカラムがソートされるURL className={TableUtil.getSortClass("name")} //このカラムがソートされている場合のクラス > <span>名前</span> </Link> </p> </th> </tr> </thead> <tbody> {tableContent} // ソートされるごとに変わるtbodyの中身 </tbody> </table> ); }
重要なのは、Link
部分が
- 自身がソートされるURL
を持つ
- 自身がソートされてる場合デザインを変更するためのクラスの付与
を行う設計する(よくありがちなやつ)。
クエリパラーメーターを連想配列にする
上記のことを行うために、クエリパラメーターを確認しどのカラムがソートされていて、昇順/降順なのか確認する必要がある。
そのために、まずはクエリパラーメーターを扱いやすいように連想配列にする。
Query.js
export function getQueryParam() { let vars = {}, max = 0, hash = "", array = ""; let url = window.location.search; hash = url.slice(1).split("&"); max = hash.length; for (let i = 0; i < max; i++) { array = hash[i].split("="); if (array[1] !== undefined) { vars[array[0]] = decodeURI(array[1]); } } return vars; }
書き方は突っ込まずに、とりあえず格納した連想配列を返している。
自身がソートされるURLを持つ
ソートされるカラムをsc
、昇順降順をsd
とする。
Table.js
export function getSortUrl(sortColumn) { let sortUrl = `${window.location.pathname}?`; let query = Query.getQueryParam(); // クエリパラメーターにscがなかった場合、受け取ったカラムでパラメーターを作る(デフォルト降順[desc]) if (!query["sc"]) { sortUrl += `sc=${sortColumn}&`; sortUrl += `sd=desc&` } for(let key in query) { // pagenationは除外 if (key === "page") { continue } // scが存在する且つ受け取ったカラムではない場合、ソートするカラムを上書き if(key === "sc" && query["sc"] !== sortColumn) { sortUrl += `${key}=${sortColumn}&`; continue; } // sdが存在する且つscが受け取ったカラムではない場合、降順にする if(key === "sd" && query["sc"] !== sortColumn) { sortUrl += `${key}=desc&`; continue; } // sdが存在する且つscが受け取ったカラムの場合、ソートの順番を逆にする if(key === "sd" && query["sc"] === sortColumn) { let sdCol = (query["sd"] === "desc")? "asc" : "desc"; sortUrl += `${key}=${sdCol}&`; continue; } // その他色々付いているクエリパラーメーターはそのままURLに含める sortUrl += `${key}=${query[key]}&`; } return sortUrl.slice(0, -1); }
だいぶゴリゴリゴリラな書き方だけど、最適化はそのうち・・・。
自身のカラムと比較してなかったらソートするカラムを追加、ある場合はソートを逆にするなど行なっている。
ソートのデザインを変更するためのクラスの付与
自身がソート対象だった場合、active
を付与してデザインを変更する。
Table.js
export function getSortClass(sortColumn) { let className = "sort"; let query = Query.getQueryParam(); if (query["sc"] === sortColumn) { className = `${className} active ${query["sd"]}`; } return className; }
CSS部分
Saas
だけと貼っておく。
.sort { position: relative; display: inline-block; padding-right: 14px; &:before { position: absolute; top: 20%; right: 0; width: 5px; height: 5px; border-right: 1px solid gray; border-bottom: 1px solid gray; content: ''; -webkit-transform: rotate(45deg); -ms-transform: rotate(45deg); transform: rotate(45deg); } &.active { &:before { border-color: red } } &.asc { &:before { top: 5px; -webkit-transform: rotate(225deg); -ms-transform: rotate(225deg); transform: rotate(225deg); } } }
終わりに
ゴリゴリゴリラだからもうちょっとクールに直したい。
今年はRedash
のあどべんとかれんだーやることなりました。