我正在寻找一种有效的方法来不断选择可见窗口/视口(viewport)中的最后一个元素。
到目前为止,这是我的代码:
$(window).scroll(function () {
$('.post-content p').removeClass("temp last")
$('.post-content p').filter(":onScreen").addClass("temp")
$(".temp").eq(-1).addClass("last")
});
正如您可能想象的那样,这会占用大量资源并且性能不佳。有人可以建议更优雅的代码吗?
我对 Javascript 的了解非常基础,所以请耐心等待。谢谢。
PS:我正在为 :onScreen 选择器使用 onScreen 插件:http://benpickles.github.com/onScreen/
最佳答案
绑定(bind)滚动处理程序
将函数绑定(bind)到滚动事件can lead to serious performance problems 。滚动事件在页面滚动时会非常强烈地触发,因此将函数与资源密集型代码绑定(bind)到它是一个坏主意。
John 建议设置时间间隔,从而让代码仅在滚动事件发生后一段时间执行。
<强> Have a look at this jsfiddle to see difference between the implementations
间接处理程序解决方案的代价是滚动和执行代码之间存在明显的延迟,您可以决定是否可以牺牲性能来换取更快的执行。请务必在您支持的每个浏览器上测试性能。
加快代码执行速度
您可以使用许多不同的概念来加速代码。关于您的代码,归结为:
- Caching selectors 。每次滚动处理程序触发时,您都会重新选择元素,这是不必要的
- 在不了解 jQuery 插件用途的情况下不使用它们。在你的情况下,the plugin code很好而且非常简单,但是为了您的目标,您可以拥有更简洁的代码。
- 防止任何不必要的计算。使用您和插件的代码,每次滚动处理程序触发时都会计算每个元素的偏移量。
所以我想出的是 a Jsfiddle with an example how you could do you scroll handler 。它与您的 DOM 不完全匹配,因为我不知道您的 html,但应该很容易将其与您的实现匹配。
与 your code 相比,我成功地将使用时间减少了 95% 。您可以通过在 chrome 中分析两个示例来亲自查看。
我假设您只想选择最后一个元素,并且不需要临时类
所以,这是带有解释的代码
// 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();
关于javascript - 如何选择视口(viewport)上的最后一个元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11598138/