Ajaxを使わない擬似的な無限スクロール風アニメーションの作り方

Ajaxを使用せずに無限スクロール風の動きを実装してみた

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の仕組み

以下のような流れでコードを組んでいます。

STEP
リストの中身をグループ分け

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;
}, []);
STEP
クラス名を付与

各グループの中の最後のliタグにjs-targetのクラス名をつけています

// 各グループの最後のliにクラスをつける
groups.forEach(function (group) {
    var lastIndex = group.length - 1;
    $(group[lastIndex]).addClass('js-target');
});
STEP
1つ目のグループ以外を非表示に

1つ目のグループ以外の透明度を0にしています。

// 1つ目のグループ以外のliタグにスタイルを設定する
$list.find('li:not(:lt(' + itemsPerGroup + '))').css({
    'opacity': 0,
});
STEP
スクロールを検知

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アニメーションを基礎から本格的に勉強するには、がオススメです。

以上、無限スクロール風のアニメーションをAjaxなしで表現する方法でした。

目次