【问题标题】:Getting Coordinates of an element on page scroll获取页面滚动元素的坐标
【发布时间】:2012-04-07 17:28:00
【问题描述】:

我遇到了这个问题,我有一组 6 个 UL,它们有一个共同的类 x。它们中的每一个都由页面的特定部分组成。现在我有 6 个与每个部分相关的菜单。我是什么必须做的是在其相关部分在用户视图中时突出显示菜单。 为此,我认为可能是 jQuery position();offset(); 可能有帮助,但它们给出了元素的顶部和左侧。我也尝试使用 jQuery viewport 插件,但显然视口很大,它一次可以显示多个 UL,因此我不能在这里应用特定于元素的逻辑。我对此并不熟悉,但元素在滚动时有什么变化吗?如果是,那么如何访问它?

请分享你的观点。

问候 Himanshu Sharma。

【问题讨论】:

    标签: javascript jquery html dom scroll


    【解决方案1】:
    1. 您可以通过$(document).width()$(document).height() 获取视口的宽度和高度
    2. 您可以通过$(document).scrollTop()$(document).scrollLeft 获取用户滚动的像素数
    3. 结合12,可以计算出视口矩形的位置
    4. 您可以使用$(element).offset()$(element).width()$(element).height() 获取元素的矩形
    5. 所以剩下的唯一事情就是确定视口的矩形是否包含(或交互)元素的矩形

    所以整个代码可能如下所示:

    /**
     * Check wether outer contains inner
     * You can change this logic to matches what you need
     */
    function rectContains(outer, inner) {
        return outer.top <= inner.top &&
            outer.bottom >= inner.bottom &&
            outer.left <= inner.left &&
            outer.right >= inner.right;
    }
    
    /**
     * Use this function to find the menu related to <ul> element
     */
    function findRelatedMenu(element) {
        return $('#menu-' + element.attr('id'));
    }
    
    function whenScroll() {
        var doc = $(document);
        var elem = $(element);
        var viewportRect = {
            top: doc.scrollTop(),
            left: doc.scrollLeft(),
            width: doc.width(),
            height: doc.height()
        };
        viewportRect.bottom = viewportRect.top + viewportRect.height;
        viewportRect.right = viewportRect.left + viewportRect.width;
    
        var elements = $('ul.your-class');
        for (var i = 0; i < elements.length; i++) {
            var elem = $(elements[i]);
            var elementRect = {
                top: elem.offset().top,
                left: elem.offset().left,
                width: elem.width(),
                height: elem.height()
            };
            elementRect.bottom = elementRect.top + elementRect.height;
            elementRect.right = elementRect.left + elementRect.width;
    
            if (rectContains(viewportRect, elementRect)) {
                findRelatedMenu(elem).addClass('highlight');
            }
        }
    }
    
    $(window).on('scroll', whenScroll);
    

    【讨论】:

    • 我会试一试,然后告诉你。
    • 为什么采用半模块化方法?我建议使用模块化或非模块化编程风格来排除混淆。当您可以在 jQuery 元素实例上使用 jQuery.each() 时,为什么还要使用 for 循环?那已经短了三行。
    【解决方案2】:

    使用 jQuery 和一个虚拟的固定 HTML 块很容易做到这一点,它可以帮助您找到视口的当前位置。

    $(window).on("scroll load",function(){  
        var once = true;
        $(".title").each(function(ele, index){
            if($(this).offset().top > $("#viewport_helper").offset().top && once){              
                var index = $(this).index(".title");
                $(".current").removeClass('current')        
                $("#menu li").eq(index).addClass('current')
                once = false;
            }
        });     
    })
    

    查看一个工作示例:http://jsfiddle.net/6c8Az/1/


    你也可以用 jQuery 插件和 :first 选择器做类似的事情:

    $(window).on("scroll load",function(){  
        $(".title:in-viewport:first").each(function(){
            var index = $(this).index(".title");
            $(".current").removeClass('current')        
            $("#menu li").eq(index).addClass('current')
        }); 
    })
    

    【讨论】:

    • 您可以使用“one”绑定 (api.jquery.com/one) 改进第一个代码块。它将摆脱 var “once”。
    • 一个用于事件绑定,而不是限制“每个”循环。
    • 你为什么不告诉我这个解决方案有什么问题,或者你为什么不给我这个问题的赏金?
    • meta.stackexchange.com/a/16067/181389 赏金可能已经过期而没有奖励,所以系统自动奖励一半。
    • 很抱歉没有时间回复这个问题。我可以在完成后奖励剩余的赏金吗?
    【解决方案3】:

    让我们看看我是否理解得很好。你有一个足够长的页面可以滚动,并且有一个元素出现在视口中时,你想用它做点什么。因此,在元素进入视口时确定触发的唯一事件是“滚动”。因此,如果元素在页面上并且滚动在视口上,您需要做的就是将一个动作绑定到滚动事件,以在每次触发事件时检查元素是否在视图中。差不多是这样的:

    $(window).scroll(function() {
       check_element_position();
    });
    

    现在,为了让您知道元素是否在视口中,您需要做 3 件事。该元素的偏移顶部、视口的大小和窗口的滚动顶部。应该看起来像这样:

    function check_element_position() {
       var win = $(window);
       var window_height = win.height();
       var element = $(your_element);
       var elem_offset_top = element.offset().top;
       var elem_height = element.height();
       var win_scroll = win.scrollTop();
       var pseudo_offset = (elem_offset_top - win_scroll);
       if (pseudo_offset < window_height && pseudo_offset >= 0) {
          // element in view
       }
       else {
          // elem not in view
       }
    }
    

    这里,(elem_offset_top - win_scroll) 表示没有滚动时的元素位置。像这样,您只需要检查元素偏移顶部是否高于窗口视口,以查看它是否在视图中。 最后,您可以通过添加元素高度(变量已经存在)来更精确地计算,因为即使元素仅 1 个像素可见,我刚刚执行的代码也会触发事件。

    注意:我刚刚在五分钟内完成了此操作,因此您可能需要修复其中的一些问题,但这让您对正在发生的事情有一个非常好的想法;)

    欢迎评论和提问

    【讨论】:

    • 非常感谢您的关注,Bene。但我会在稍后的某个时间告诉您。如果有效,我会将赏金奖励给您。谢谢
    猜你喜欢
    • 2018-09-11
    • 2016-08-27
    • 2016-05-11
    • 2019-07-19
    • 1970-01-01
    • 2011-09-27
    • 1970-01-01
    • 1970-01-01
    • 2015-06-22
    相关资源
    最近更新 更多