2

我正在寻找一种有效的方法来不断选择可见窗口/视口中的最后一个元素。

到目前为止,这是我的代码:

$(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/

4

1 回答 1

2

绑定滚动处理程序

将函数绑定到滚动事件会导致严重的性能问题。scroll 事件在页面滚动时会非常激烈地触发,因此将函数与资源密集型代码绑定到它是一个坏主意。

John 建议设置间隔,从而让代码仅在滚动事件后的一段时间内执行。

看看这个 jsfiddle 看看实现之间的区别

间接处理程序解决方案的代价是滚动和执行代码之间存在明显的延迟,您可以决定是否可以用性能换取更快的执行。请务必在您支持的每个浏览器上测试性能。

加速代码执行

您可以使用许多不同的概念来加速您的代码。关于您的代码,归结为:

  • 缓存选择器。每次滚动处理程序触发时都重新选择元素,这是不必要的
  • 在不知道它们做什么的情况下不使用 jQuery 插件。在您的情况下,插件代码很好而且非常简单,但是为了您的目标,您可以拥有更快速的代码。
  • 防止任何不必要的计算。使用您和插件的代码,每次滚动处理程序触发时都会计算每个元素的偏移量。

所以我想出的是一个带有示例的 Jsfiddle,你可以如何滚动处理程序。它与您的 DOM 不完全匹配,因为我不知道您的 html,但应该很容易将它与您的实现匹配。

与您的代码相比,我设法将使用的时间减少了 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();
于 2012-07-22T09:08:03.980 回答