あるギャラリーサイトを作成しているときに、要件として
ページ読み込みのたびにギャラリーの表示順をランダムで変更できますか?
と相談されました。
クラスをつけてcssでorder
で順番を変更しても良いけどめんどくさそう…
jsでできたら楽かな?と思ったのですがなかなか調べても出てこなかったのでコード書いて実装しました。
では早速いってみましょう。
まずはコードから
See the Pen jsでページ読み込み時にリストの順番をランダムに変更する by 東野江里 (@anyxfbuk-the-scripter) on CodePen.
何度かページ読み込んでもらえればランダム表示になっているのがわかると思います。
解説
html
<ul class="list">
<li class="list-item">リスト①</li>
<li class="list-item">リスト②</li>
<li class="list-item">リスト③</li>
<li class="list-item">リスト④</li>
<li class="list-item">リスト⑤</li>
<li class="list-item">リスト⑥</li>
<li class="list-item">リスト⑦</li>
<li class="list-item">リスト⑧</li>
<li class="list-item">リスト⑨</li>
<li class="list-item">リスト⑩</li>
</ul>
特筆すべきことはないですが、並べ替えたい要素には同じクラス(今回はlist-item
)をつけて、同じ階層に並べてください。
cssは今回はつけていないので各々でどうぞ。
js
1. shuffleElements();
shuffleElements();
ページ読み込み時に shuffleElements
関数が実行されます。リストアイテムをシャッフルするのがこの関数の目的です。
2. randomBox
の取得
let randomBox = document.querySelectorAll('.list');
.list
クラスを持つ要素をすべて取得し、randomBox
という変数に格納します。これは NodeList
と呼ばれる配列風のオブジェクトで、複数の .list
要素を操作するために使われます。
3.要素が存在するかのチェック
if (!randomBox || randomBox === 0) {
return;
}
.list
要素が存在しない場合や、randomBox
が空の場合には何もしないで関数を終了します。これにより、エラーを防ぎます。
4.各 .list
内の .list-item
を取得
for (let i = 0; i < randomBox.length; i++) {
let elements = randomBox[i].querySelectorAll('.list-item');
取得した .list
要素のそれぞれに対してループを回し、各 .list
の中にある .list-item
要素をすべて取得して elements
に格納します。
5. .list-item
が存在するかのチェック
if (!elements || elements.length === 0) {
return;
}
.list-item
要素が存在しない場合は、関数を終了します。
6. Array.from()
を使って配列に変換
let elementsArray = Array.from(elements);
NodeList
は通常の配列ではないため、Array.from()
を使って配列に変換しています。これにより、配列操作がしやすくなります。
7.Fisher-Yatesアルゴリズムで配列をシャッフル
for (let j = elementsArray.length - 1; j > 0; j--) {
let randomIndex = Math.floor(Math.random() * (j + 1));
[elementsArray[j], elementsArray[randomIndex]] = [elementsArray[randomIndex], elementsArray[j]];
}
Fisher-Yatesアルゴリズムを使用して、配列をランダムに並び替えます。randomIndex
には、0
から j
の範囲でランダムなインデックスを生成し、elementsArray[j]
と elementsArray[randomIndex]
を入れ替えます。この操作をリストの末尾から開始し、要素をシャッフルします。
8.元のリストをクリア
while (randomBox[i].firstChild) {
randomBox[i].removeChild(randomBox[i].firstChild);
}
.list
内のすべての子要素を削除します。これにより、既存の .list-item
要素が一旦消去されます。
9.シャッフルされた要素を再配置
elementsArray.forEach(function(element) {
randomBox[i].appendChild(element);
});
シャッフルされた elementsArray
の要素を .list
内に再び追加します。appendChild
を使って、並び替えた要素を元の .list
に再挿入しています。
まとめ
アルゴリズムとしては
.list
の各リストにある.list-item
をランダムにシャッフル- 元の
.list
の内容をクリアし、シャッフル後の順番で.list-item
を再配置
という感じです。なので、.list
が複数あってもすべて同じようにランダム表示のコードが動くはずです。
ぜひ使ってみてください。
もしわからないことあれば質問ください!
記事にしてほしい・解説してほしい内容のリクエストもお待ちしています。