使用getBoundingClientRect()来获取页面元素的位置

判断网页中element是否可见

以前一直用jQurey的is(“:visible”)来判断。一次偶然在chrome中发现这个函数居然是消耗CPU最多的,这个函数效率很低!
经过一翻搜寻,终于找到了它:getBoundingClientRect——获取element实际的top、bottom、left、right定位值,我们利用它计算element的高度,如果为0,即可认为element不可见。关键是,几乎所有浏览器都支持getBoundingClientRect(下文有详细说明)

function isVisible(element) {
    var rect = element[0].getBoundingClientRect();
    return !!(rect.bottom - rect.top);
}

如何理解getBoundingClientRect

document.documentElement.getBoundingClientRect

下面这是MSDN的解释:

Syntax

oRect = object.getBoundingClientRect()

Return Value

Returns a TextRectangle object. Each rectangle has four integer properties (top, left, right, and bottom) that represent a coordinate of the rectangle, in pixels.

Remarks

This method retrieves an object that exposes the left, top, right, and bottom coordinates of the union of rectangles relative to the client’s upper-left corner. In Microsoft Internet Explorer 5, the window’s upper-left is at 2,2 (pixels) with respect to the true client.

还是实际解释下,该方法获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置。

该方法已经不再是IE Only了,FF3.0+和Opera9.5+已经支持了该方法,可以说在获得页面元素位置上效率能有很大的提高,在以前版本的Opera和Firefox中必须通过循环来获得元素在页面中的绝对位置。

获取页面元素的位置

以前绝大多数的使用下面的代码来获取页面元素的位置:

var _x = 0, _y = 0;
do {
    _x += el.offsetLeft;
    _y += el.offsetTop;
} while(el=el.offsetParent);
return {x: _x, y: _y};

这里有个”offsetParent”问题,所以要写很多兼容的代码,经过不懈的查找终于找到getBoundingClientRect();该方法获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置,他返回的是一个对象,即Object,该对象有是个属性:top,left,right,bottom;这里的top、left和css中的理解很相似,但是right,bottom和css中的理解有点不一样,看示意图:

下面的代码举了个简单的例子,可以滚动滚动条之后点红色区域看各个值的变化。

有了这个方法,获取页面元素的位置就简单多了,

var X= this.getBoundingClientRect().left+document.documentElement.scrollLeft;
var Y =this.getBoundingClientRect().top+document.documentElement.scrollTop;

各种常用浏览器getBoundingClientRect的解析

先上测试代码

下面是alert结果: 

  • IE、FF、Chrome:208
  • IE内核的Maxthon:215
  • IE内核的TheWorld:217
  • 当body加上margin:0;padding:0 的时候IE、FF、Chrome、Maxthon下均为200,而只有TheWorld为202
  • 然后把HTML代码头部的DOCTYPE声明去掉的时候FF、Chrome、Maxthon值均为200,而IE由于进入Quirks模式,此时的值为202,而TheWorld仍为为202

结论:
FF、Chrome、Maxthon为始终坚持标准模式(Standards Mode),IE在加了声明后也进入标准模式(Standards Mode),只有TheWorld始终坚持Quirks模式,万恶!

建议: 
为了兼容把body加上margin:0;padding:0,注意加DOCTYPE声明(有了它IE还是挺听话的)

JQuery中的解决方法

getBoundingClientRect方法,原是IE中提供用于获取页面中某个元素的位置(相对于浏览器左上角)的,Firefox在3.0(?)以后也提供了这个方法,并且在Firefox3.5后的版本中,能够获取到元素的高度和宽度属性。

假设页面上有一个元素,使用getBoundingClientRect方法获取它位置属性的方法如下:

var rect = el.getBoundingClientRect(),
    left = rect.left,
    top = rect.top,
    right = rect.right,
    bottom = rect.bottom,
    width = rect.width,    //IE中无法获取
    height = rect.height;    //IE中无法获取 

但是在IE下有点小问题:
页面左上角由一个元素,紧贴浏览器的左边和上边,在除IE外的浏览器,包括基于IE内核的搜狗浏览器(360垃圾浏览器及TT浏览器未测试)都能正确的获取到各个属性的值,而在IE中,每个值都会比正常值多出两个像素,例如,正常的left值为0,在IE中为2;
这是因为IE中document.documentElement.clientTop并不为0(尽管已设置html、body的margin和padding为0),所以在IE中获得的值要减去document.documentElement.clientTop的值。

下面是JQuery中解决方法:

var getOffset = function(el){
    var box = el.getBoundingClientRect(),
    doc = el.ownerDocument,
    body = doc.body,
    docElem = doc.documentElement,

    // for ie
    clientTop = docElem.clientTop || body.clientTop || 0,
    clientLeft = docElem.clientLeft || body.clientLeft || 0,

    // In Internet Explorer 7 getBoundingClientRect property is treated as physical,
    // while others are logical. Make all logical, like in IE8.

    zoom = 1;
    if (body.getBoundingClientRect) {
        var bound = body.getBoundingClientRect();
        zoom = (bound.right - bound.left)/body.clientWidth;
    }
    if (zoom > 1){
        clientTop = 0;
        clientLeft = 0;
    }
    var top = box.top/zoom + (window.pageYOffset || docElem && docElem.scrollTop/zoom || body.scrollTop/zoom) - clientTop,
    left = box.left/zoom + (window.pageXOffset|| docElem && docElem.scrollLeft/zoom || body.scrollLeft/zoom) - clientLeft;

    return {
        top: top,
        left: left
    };
}

getClientRects 和 getBoundingClientRect 的区别

TextRectangle

对于文本对象,W3C提供了一个 TextRectangle 对象,这个对象是对文本区域的一个解释。

看下图(截图来源ppk):

一行连续的文本

我们可以获取到里面的5行文字,红色框就是TextRectangle这个抽象的对象.

TextRectangle对象包含了, top left bottom left四个属性,这四个属性都是对应可视区域viewport的

理解TextRectangle后,对getClientRects和getBoundingClientRect可以得到一个更好的说明.

getClientRects 返回一个TextRectangle集合,就是TextRectangleList对象。
getBoundingClientRect 返回 一个TextRectangle对象。

浏览器差异:

除了safari,firefox2.0外所有浏览器都支持getClientRects和getBoundingClientRect,
firefox 3.1给TextRectangle增加了 width 和 height。

ie 和非ie浏览器在使用getClientRects还是有些差别的,ie获取TextRectangleList的范围很大。而非ie获取的范围比较小, 只有display:inline的对象才能获取到TextRectangleList,例如em i span 等标签。

使用场景:

现 在用得最多的是getBoundingClientRect,这个直接返回一个TextRectangle,其实大家经常使用它来获取到一个 element的viewport坐标.其实就算dom里面没有文本也能返回一个 TextRectangle. 这样就不需要向上遍历来计算对象的相对坐标了。

最后,有什么问题,大家可以给我留言哦,别忘了关注我的博客哦:

http://list.qq.com/cgi-bin/qf_invite?id=b6eb34388fd016582957d6e50d005146e24fe6b166ee66c0



此条目发表在Javascript分类目录,贴了, , 标签。将固定链接加入收藏夹。