スクロール ハンドラのバインド
関数をスクロール イベントにバインドすると、重大なパフォーマンスの問題が発生する可能性があります。スクロール イベントは、ページ スクロール時に非常に活発に発生するため、リソースを大量に消費するコードで関数をバインドすることはお勧めできません。
John が提案しているのは、間隔を設定して、スクロール イベントの後のしばらくの間だけコードを実行することです。
このjsfiddleを見て、実装の違いを確認してください
間接ハンドラー ソリューションは、コードのスクロールと実行の間に顕著な遅延が生じるという代償を払っています。サポートするすべてのブラウザでパフォーマンスをテストしてください。
コード実行の高速化
コードを高速化するために使用できるさまざまな概念がたくさんあります。コードに関しては、次のようになります。
- セレクターのキャッシング。スクロール ハンドラが起動するたびに要素を再選択しますが、これは不要です。
- jQuery プラグインの機能を知らずに使用しない。あなたの場合、プラグイン コードは素晴らしく、非常に単純ですが、目的のためには、よりスマートなコードを使用することもできます。
- 不要な計算を防ぎます。プラグインのコードを使用すると、スクロール ハンドラが起動するたびにすべての要素のオフセットが計算されます。
だから私が思いついたのは、スクロールハンドラをどのように行うことができるかの例を含む Jsfiddle です。私はあなたのHTMLを知らないので、あなたのDOMと完全には一致していませんが、あなたの実装と一致させるのは簡単なはずです。
あなたのコードと比較して、使用時間を 95% 削減することができました。クロムで 2 つのサンプルをプロファイリングすることで、自分の目で確かめることができます。
最後の要素を選択したいだけで、一時クラスは必要ないと思いました
だから、ここに説明付きのコードがあります
// Store the offsets in an array
var offsets = [];
// Cache the elements to select
var elements = $('.elem');
// Cache the window jQuery Object
var jWindow = $(window);
// Cache the calculation of the window height
var jWindowHeight = jWindow.height();
// set up the variable for the current selected offset
var currentOffset;
// set up the variable for the current scrollOffset
var scrollOffset;
// set up the variable for scrolled, set it to true to be able to assign at
// the beginning
var scrolled = true;
// function to assign the different elements offsets,
// they don't change on scroll
var assignOffsets = function() {
elements.each(function() {
offsets.push({
offsetTop: $(this).offset().top,
height: $(this).height(),
element: $(this)
});
});
};
// execute the function once. Exectue it again if you added
// or removed elements
assignOffsets();
// function to assign a class to the last element
var assignLast = function() {
// only execute it if the user scrolled
if (scrolled) {
// assigning false to scrolled to prevent execution until the user
// scrolled again
scrolled = false;
// assign the scrolloffset
scrollOffset = jWindowHeight + jWindow.scrollTop();
// only execute the function if no current offset is set,
// or the user scrolled down or up enough for another element to be
// the last
if (!currentOffset || currentOffset.offsetTop < scrollOffset || currentOffset.offsetTop + currentOffset.height > scrollOffset) {
// Iterate starting from the bottom
// change this to positive iteration if the elements count below
// the fold is higher than above the fold
for (var i = offsets.length - 1; i >= 0; i--) {
// if the element is above the fold, reassign the current
// element
if (offsets[i].offsetTop + offsets[i].height < (scrollOffset)) {
currentOffset && (currentOffset.element.removeClass('last'));
currentOffset = offsets[i];
currentOffset.element.addClass('last');
// no further iteration needed and we can break;
break;
}
}
return true;
} else {
return false;
}
}
}
assignLast();
// reassign the window height on resize;
jWindow.on('resize', function() {
jWindowHeight = jWindow.height();
});
// scroll handler only doing assignment of scrolled variable to true
jWindow.scroll(function() {
scrolled = true;
});
// set the interval for the handler
setInterval(assignLast, 250);
// assigning the classes for the first time
assignLast();