【问题标题】:How do I get the offset().top value of an element without using jQuery?如何在不使用 jQuery 的情况下获取元素的 offset().top 值?
【发布时间】:2013-09-27 23:44:02
【问题描述】:

我正在使用 Angular 框架编写单页应用程序。我是新手。我已阅读 this guide 以帮助我了解 jQuery 和 Angular 之间的根本区别,并且我想尽可能地遵循本指南而不使用 jQuery。

除了 jQuery 有助于解决一些浏览器不兼容问题并提供有用的函数库,例如能够从窗口顶部知道元素的顶部位置,如 $('element').offset().top。如果不重写此函数,似乎没有普通的 Javascript 能够接近,此时使用 jQuery 或类似 jQuery 的库不是 更好的主意吗?

具体来说,我要做的是设置一个指令,一旦元素的顶部滚动到窗口中的某个位置,就可以将其固定到位。这是它的样子:

directives.scrollfix = function () {
    return {
        restrict: 'C',
        link: function (scope, element, $window) {

            var $page = angular.element(window)
            var $el   = element[0]
            var elScrollTopOriginal = $($el).offset().top - 40

            $page.bind('scroll', function () {

                var windowScrollTop = $page[0].pageYOffset
                var elScrollTop     = $($el).offset().top

                if ( windowScrollTop > elScrollTop - 40) {
                    elScrollTopOriginal = elScrollTop - 40
                    element.css('position', 'fixed').css('top', '40px').css('margin-left', '3px');
                }
                else if ( windowScrollTop < elScrollTopOriginal) {
                    element.css('position', 'relative').css('top', '0').css('margin-left', '0');
                }
            })

        }
    }
}

如果在 Angular 中有更好的方法来实现这一点,但我仍然没有得到,我会很感激你的建议。

【问题讨论】:

  • 接受的解决方案不考虑当前滚动位置,请参阅下面的答案

标签: jquery angularjs window offset scrolltop


【解决方案1】:

如果$el 是实际的DOM 对象,则使用getBoundingClientRect

var top = $el.getBoundingClientRect().top;

JSFiddle

Fiddle 将显示这将获得与 jquery 的偏移量顶部相同的值

编辑:如 cmets 中所述,这不考虑滚动内容,下面是 jQuery 使用的代码

https://github.com/jquery/jquery/blob/master/src/offset.js (5/13/2015)

offset: function( options ) {
    //...

    var docElem, win, rect, doc,
        elem = this[ 0 ];

    if ( !elem ) {
        return;
    }

    rect = elem.getBoundingClientRect();

    // Make sure element is not hidden (display: none) or disconnected
    if ( rect.width || rect.height || elem.getClientRects().length ) {
        doc = elem.ownerDocument;
        win = getWindow( doc );
        docElem = doc.documentElement;

        return {
            top: rect.top + win.pageYOffset - docElem.clientTop,
            left: rect.left + win.pageXOffset - docElem.clientLeft
        };
    }
}

【讨论】:

  • 看起来跨浏览器的兼容性也很好。谢谢。
  • 请注意,此解决方案不考虑当前滚动位置,请参阅下面的答案
  • 不,不一样。这是一样的:$el.getBoundingClientRect().top + document.body.scrollTop
  • 嗯,jQuery 使用的不止这些……你应该包括getWindowisWindow 等等……
  • @TJ,为什么?用户应该能够推断 getWindow 做了什么,可以自己查找实用程序函数的代码,因为我已经链接了 github 存储库,并且我相信添加代码只是为了解释实用程序函数只会使答案变得混乱。
【解决方案2】:

Patrick Evans 接受的解决方案不考虑滚动。 我稍微改变了他的 jsfiddle 来证明这一点:

css:添加一些随机高度以确保我们有一些空间可以滚动

body{height:3000px;} 

js: 设置一些滚动位置

jQuery(window).scrollTop(100);

因此两个报告的值现在不同:http://jsfiddle.net/sNLMe/66/

2015 年 2 月 14 日更新

有一个 jqLit​​e 等待的拉取请求,包括它自己的偏移方法(照顾当前滚动位置)。如果您想自己实现它,请查看源代码:https://github.com/angular/angular.js/pull/3799/files

【讨论】:

  • cvmlrobotics 链接已失效。
  • @user2602152 感谢您的评论,我已经用我最近发现的其他信息替换了死链接。
【解决方案3】:

你可以试试 element[0].scrollTop,在我看来这个解决方案更快。

这里有更大的例子 - http://cvmlrobotics.blogspot.de/2013/03/angularjs-get-element-offset-position.html

【讨论】:

  • cvmlrobotics 的链接已失效。
【解决方案4】:

看来你可以只在角度元素上使用 prop 方法:

var top = $el.prop('offsetTop');

为我工作。有人知道这样做有什么缺点吗?

【讨论】:

  • 当我使用 element.prepend() 向 DOM 添加一个元素时; offsetTop 和 Left 始终为 0。但是在元素检查器中,它不是 0。
  • offsetTop 属性只返回相对于元素父元素的偏移量 (developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetTop),而不像 jQuery 的 offset() (api.jquery.com/offset) 那样返回整个文档的偏移量。
  • 在函数在第一次通过摘要时查找 $el 后异步加载 DOM 元素的情况下,这有点复杂。结合 Darren 提供的解决方案 - 我必须首先使用普通的 JS querySelector,将其包装在 angular 元素中,然后才能调用 prop。
【解决方案5】:

这是一个无需 jQuery 即可完成的函数:

function getElementOffset(element)
{
    var de = document.documentElement;
    var box = element.getBoundingClientRect();
    var top = box.top + window.pageYOffset - de.clientTop;
    var left = box.left + window.pageXOffset - de.clientLeft;
    return { top: top, left: left };
}

【讨论】:

  • 重新发明轮子(顺便说一句,不是通用的)肯定比使用“癌症”更好,是的,当然......
  • @Regent 并不是每个人都希望包含一个巨大的库来完成原本可以用 5 行代码完成的事情。
  • 例如 jquery-2.1.3.min.js (83KB) 不是大文件。在很多地方使用 jQuery 的项目(不是 AngularJS 的项目)呢?您是否建议编写您的一个函数来缩短代码(与 DOM 一起使用)?没有很好的测试,有错误,没有很好的交叉浏览?我知道 jQuery 不应该在所有项目中使用,但是通过侮辱 jQuery 你声明它不应该在任何地方使用(这是错误的陈述,由方式),不是吗?
  • 我不确定我在哪里说过它“不应该在任何地方使用”。如果 jQuery 已经是必需品,那么请务必使用它。但随着时间的推移和浏览器不兼容问题的解决,它的价值开始下降。虽然 83kb 在您的第一世界光纤连接中可能不是很多,但大部分发展中国家并不那么幸运。作为一个 JS 库设计者,当你真正需要了解事情是如何工作的时候,有这么多 SO 帖子不断地转向 jQuery,这也令人沮丧。见youmightnotneedjquery.com
  • 我一直在寻找这样的答案,但我发现的只是 jQuery 代码。我认为大多数人都将 JS 与 JQ 混淆了。现在我了解了词缀环境中的工作原理!谢谢!
【解决方案6】:

对于 Angular 2+ 来获取当前元素的偏移量(this.el.nativeElement 相当于 jquery 中的 $(this)):

export class MyComponent implements  OnInit {

constructor(private el: ElementRef) {}

    ngOnInit() {
      //This is the important line you can use in your function in the code
      //-------------------------------------------------------------------------- 
        let offset = this.el.nativeElement.getBoundingClientRect().top;
      //--------------------------------------------------------------------------    

        console.log(offset);
    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-07
    相关资源
    最近更新 更多