これは取り組むのが楽しい問題でした。
このソリューションは、div を配列に配置し、最後にスクロールした要素の配列インデックスを記憶します。スクロール イベントがトリガーされると、新しい scrollTop が現在の div の上部オフセットの上または下にあるかどうかがチェックされ、それに応じて配列内の次または前の div に移動します。
このソリューションでは、多くの div を使用できます。高速にスクロールしたときに発生するちらつきを取り除こうとしましたが、それを行う唯一の方法は、アニメーション中にスクロールバーを無効にすることだと思います.
http://jsfiddle.net/dUVmh/35/
$(function() {
var divs = [],
body = $('body, html'),
currentDiv = 0,
timeout;
$('div').each(function() {
divs.push($(this));
});
// we only need to capture the first scroll event triggered and then
// add another listener once we have done our animation
var scrollListen = function() {
$(window).one('scroll', function() {
doScroll($(this).scrollTop());
});
};
// Without the timeout, the scroll event would be triggered again too soon
var scrollEnd = function() {
clearTimeout(timeout);
timeout = setTimeout(function() {
scrollListen();
}, 10);
};
// checks if the scroll direction was up and down and animates
// the body scrollTop to the next or previous div
var doScroll = function(scrollTop) {
var direction = scrollTop - divs[currentDiv].offset().top;
if (direction > 0 && currentDiv + 1 < divs.length) {
nextDiv = currentDiv + 1;
} else if (currentDiv - 1 > -1) {
nextDiv = currentDiv - 1;
}
if (currentDiv === nextDiv) {
scrollEnd();
}
body.animate({
scrollTop: divs[nextDiv].offset().top
}, 1000, function() {
currentDiv = nextDiv;
scrollEnd();
});
};
scrollListen();
});
編集: Firefox の scrollTop は、本文ではなく html で変更する必要があります。また、firefox が一度に複数回 scrollListen を呼び出す際の問題も修正されました。