jQuery:视口内选择器精度

时间:2013-11-04 21:38:39

标签: javascript jquery scroll viewport

我有一个容器,里面有多个<div>,表示页面。当用户滚动浏览这些页面时,我想更新当前页码标签。为此,我发现我可以使用 :in-viewport 选择器。我尝试了这个example,并提出了这个jsFiddle:

http://jsfiddle.net/j2aet/

这似乎有效,但我确实遇到了一个小问题。这就是当我向下滚动时,我的当前页码不会更改为“2”,直到第二个“图像”元素被部分隐藏(在顶部),并且页面3部分可见。我希望它能早点改为2。请参阅此屏幕截图,我的意思是,这是当它变为“2”时:

http://imgur.com/l40ddBs

理想情况下,只要第二个“image”元素是视图中占多数的元素,我就希望当前页码更改为“2”。例如,这是关于我希望将当前页码更改为“2”的位置:

http://imgur.com/uKZRD4m(注意#2是多数在视图中)

随着我继续滚动,它似乎变得更糟。在下一个屏幕截图中,当前页码仍然显示为5,但第5张图像根本不在视图中了!

http://imgur.com/tr10aoU

我能做些什么不同才能达到这个效果?现在我只是将in:viewport选择器与:first选择器结合使用:

$('.item:in-viewport:first')

2 个答案:

答案 0 :(得分:1)

这是一种可以尝试在向上滚动时检查每个项目的位置的方法。 这不是完美的,它是更多的代码,但希望这将有助于给你一些想法。

以下是fiddle示例,以下是代码。

$container.off('scroll').on('scroll', function () {
    var top = $(this).offset().top;

    $(".item").each(function()
    {  
        var itemTop = $(this).offset().top;
        var itemBottom = $(this).offset().top + $(this).height(); 
        if(itemTop >= (top + 25) && itemTop <= (top + 50))
            $cp.html($(this).attr("page"));
        else if(itemBottom >= (top + 400) && itemBottom <= (top + 425))
            $cp.html($(this).attr("page"));

    });
});

答案 1 :(得分:1)

这是我最终的目标:

$container.on('scroll', function () {
    // for each item in viewport, which one is in view the MOST?
    var diff = null;
    var num;
    $('.item:in-viewport').each(function(){
        var thisPage = $(this).attr("page");
        var thisTop = $(this).position().top;

        if(diff == null){
            diff = Math.abs(containerTop - thisTop);
            num = thisPage;
        } else {
            var temp = Math.abs(containerTop - thisTop);
            if(temp < diff) {
                diff = temp;
                num = thisPage;
            }
        }
    });
    diff = null;
    $cp.html(num);
});

http://jsfiddle.net/j2aet/1/

我仍然可以使用:in-viewport选择器,但我只是将其与:first选择器组合在一起,我只是遍历视图中的每个项目,并确定哪一个最接近顶部容器。可能有一种更有效的方法可以做到这一点,但现在这将有效。

更新(针对效果):

根据我发现 here 的想法,我们可以选择仅在用户完成滚动至少半秒后才更新页码:

$container.on('scroll', function () {
    if(this.scrollTo) clearTimeout(this.scrollTo);
    this.scrollTo = setTimeout(function () { updatePageNumber();}, 500);
});

function updatePageNumber(){
    // for each item in viewport, which one is in view the MOST?
    var diff = null;
    var num;
    $('.item:in-viewport').each(function(){
        var thisPage = $(this).attr("page");
        var thisTop = $(this).position().top;

        if(diff == null){
            diff = Math.abs(containerTop - thisTop);
            num = thisPage;
        } else {
            var temp = Math.abs(containerTop - thisTop);
            if(temp < diff) {
                diff = temp;
                num = thisPage;
            }
        }
    });
    diff = null;
    $cp.html(num);
}

http://jsfiddle.net/j2aet/2/