Ajaxを使えない環境で無限スクロールのようなアニメーションをつけてほしいという要望があり作成してみました。基本的にはJavaScript(jQuery)のみで制御しています。
擬似的な無限スクロール風アニメーションを実装した例
上記のデモを開き、下の方にスクロールしてご確認ください。
最初に画像を5件表示していて、スクロールするごとに追加の5件が表示されます。一見すると無限スクロールのように見えますが、単純なスクロールアニメーションです。
コードの見本
HTML
<ul class="js-list">
<li><img src="https://picsum.photos/400/300"></li>
<li><img src="https://picsum.photos/400/300"></li>
<li><img src="https://picsum.photos/400/300"></li>
<li><img src="https://picsum.photos/400/300"></li>
<li><img src="https://picsum.photos/400/300"></li>
<li><img src="https://picsum.photos/400/300"></li>
<li><img src="https://picsum.photos/400/300"></li>
<li><img src="https://picsum.photos/400/300"></li>
<li><img src="https://picsum.photos/400/300"></li>
<li><img src="https://picsum.photos/400/300"></li>
...続く
</ul>
HTMLはとてもシンプルで、クラス名「js-list」の要素の中に、liタグがたくさん入っている構造です。
JavaScript
あらかじめjQueryを読み込んでおく必要があります。
$(document).ready(function () {
var $list = $('.js-list');
var itemsPerGroup = 5;
// liをグループに分ける
var groups = $list.find('li').toArray().reduce(function (acc, item, index) {
var groupIndex = Math.floor(index / itemsPerGroup);
if (!acc[groupIndex]) {
acc[groupIndex] = [];
}
acc[groupIndex].push(item);
return acc;
}, []);
// 各グループの最後のliにクラスをつける
groups.forEach(function (group) {
var lastIndex = group.length - 1;
$(group[lastIndex]).addClass('js-target');
});
// 1つ目のグループ以外のliタグにスタイルを設定する
$list.find('li:not(:lt(' + itemsPerGroup + '))').css({
'opacity': 0,
});
$(window).scroll(function () {
var windowHeight = $(window).height();
var windowMiddle = windowHeight / 2;
$('.js-target').each(function () {
var target = $(this);
var targetTop = target.offset().top;
var targetMiddle = targetTop + target.outerHeight() / 2;
var scrollPosition = $(window).scrollTop() + windowMiddle;
if (scrollPosition >= targetMiddle) {
var targetIndex = groups.findIndex(function (group) {
return group.indexOf(target[0]) !== -1;
});
var nextGroup = groups[targetIndex + 1];
if (nextGroup) {
if (nextGroup) {
$(nextGroup).animate({
'opacity': 1,
}, 500); // アニメーションの時間を500msに設定
}
}
}
});
});
});
3行目のvar itemsPerGroup = 5;
のところで最初に表示する件数と、スクロールに応じて表示する件数を設定しています。10件づつ表示する場合はvar itemsPerGroup = 10;
としてください。
JavaScriptの仕組み
以下のような流れでコードを組んでいます。
js-listの中のliタグを、5つで1つのグループに分けています。
// liをグループに分ける
var groups = $list.find('li').toArray().reduce(function (acc, item, index) {
var groupIndex = Math.floor(index / itemsPerGroup);
if (!acc[groupIndex]) {
acc[groupIndex] = [];
}
acc[groupIndex].push(item);
return acc;
}, []);
各グループの中の最後のliタグにjs-target
のクラス名をつけています
// 各グループの最後のliにクラスをつける
groups.forEach(function (group) {
var lastIndex = group.length - 1;
$(group[lastIndex]).addClass('js-target');
});
1つ目のグループ以外の透明度を0にしています。
// 1つ目のグループ以外のliタグにスタイルを設定する
$list.find('li:not(:lt(' + itemsPerGroup + '))').css({
'opacity': 0,
});
js-target
のtopがビューポートのセンターを通過したら次のグループを表示しています。
$(window).scroll(function () {
var windowHeight = $(window).height();
var windowMiddle = windowHeight / 2;
$('.js-target').each(function () {
var target = $(this);
var targetTop = target.offset().top;
var targetMiddle = targetTop + target.outerHeight() / 2;
var scrollPosition = $(window).scrollTop() + windowMiddle;
if (scrollPosition >= targetMiddle) {
var targetIndex = groups.findIndex(function (group) {
return group.indexOf(target[0]) !== -1;
});
var nextGroup = groups[targetIndex + 1];
if (nextGroup) {
if (nextGroup) {
$(nextGroup).animate({
'opacity': 1,
}, 500); // アニメーションの時間を500msに設定
}
}
}
});
});
以上の流れをliタグがなくなるまで繰り返し処理を行っています。
Ajaxを使用していないため、ページを読み込んだ段階でページ内の全てのデータが読み込まれます。繰り返す画像や投稿がとても多い場合は、ページの読み込みに時間を要する場合がありますのでご注意ください。
Webアニメーションを基礎から本格的に勉強するには、1冊ですべて身につくJavaScript入門講座がオススメです。
以上、無限スクロール風のアニメーションをAjaxなしで表現する方法でした。