我想达到的目标:
- 如果用户从顶部(原点)滚动超过24px,做一些事情。
- 如果用户在顶部(原点)的24px范围内滚动,则反转一次。
我有这样的代码:
$("#box").scroll(function(){
var ofs = $(".title").offset().top;
if (ofs <= 24)
// Do something
else
// Reverse that something
})
根据我的理解,这个函数在每次用户滚动时都运行,这可能导致对DOM的数百次调用。- 这不是每一个资源效率-有更被动的方法吗?
- 两个条件都被反复触发,即使是小的滚动量-如果相同的条件是真的,任何方法执行代码只一次而不重复?
您想要做的是限制请求或所谓的"debounce"。Throttling只允许在一段时间内调用一定数量的函数,debounce只在动作停止后的一段时间内调用该函数。
这是一个很好的解释链接:https://css-tricks.com/the-difference-between-throttling-and-debouncing/
有几个库可以为你做这个,比如Underscore和Lodash。你也可以滚动你自己的,debounce的基本前提是:
var timer;
$('#box').scroll(function(){
//cancel and overwrite timer if it exists already
// set timer to execute doWork after x ms
})
function doWork(){
//do stuff
}
你也可以考虑使用requestAnimationFrame
取决于浏览器的支持。requestAnimationFrame的例子,它看起来支持大多数现代浏览器和IE>= 10
在下面的代码中,每次用户滚动超过或低于25px阈值时,将调用if ($boxAboveBelow)
if语句中的一个条件。
var $box = $('#box');
var $boxAboveBelow = true; // true above, false below
$box.on('scroll', function() { // Throttle this function if needed
var newAboveBelow = $box.scrollTop() < 25;
if (newAboveBelow !== $boxAboveBelow) {
$boxAboveBelow = newAboveBelow;
if ($boxAboveBelow) {
// If the user scrolls back within 24px of the top (origin), reverse that something once.
} else {
// If user has scrolled more than 24px from the top (origin), do something once.
}
}
})
如果你需要这些条件只被调用一次,你可以设置布尔变量来记录这些条件是否被调用过。
var aboveCalled = false;
var belowCalled = false;
var $box = $('#box');
var $boxAboveBelow = true; // true above, false below
$box.on('scroll', function() { // Throttle this function if needed
var newAboveBelow = $box.scrollTop() < 25;
if (newAboveBelow !== $boxAboveBelow) {
$boxAboveBelow = newAboveBelow;
if ($boxAboveBelow) {
!aboveCalled && doScrollAboveStuff();
aboveCalled = true;
} else {
!belowCalled && doScrollBelowStuff();
belowCalled = true;
}
if (aboveCalled && belowCalled) {
$box.off('scroll'); // No need to keep listening, since both called
}
});