如何选择视口上的最后一个元素

时间:2012-07-22 06:15:31

标签: javascript constants 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/

1 个答案:

答案 0 :(得分:1)

绑定滚动处理程序

将函数绑定到滚动事件can lead to serious performance problems。滚动事件在页面滚动时非常激烈地触发,因此将具有大量资源代码的函数绑定到它是一个坏主意。

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();