相信搞前端开发的朋友们都遇到过这个问题,网上有很多讨论它的文章,但似乎都没有给出一个很完美的解决方案。本文试图用传统的递归offsetLeft,offsetTop的方法来获得元素的绝对坐标,并通过这个过程加深对DOM盒模型的理解,将其中易混淆的属性如offsetLeft,scrollLeft分辨开来。

  1. 支持的浏览器

  针对目前的情况,支持ie6+, 以及firefox,chrome,opera,safari的最新版本(这里偷个懒,所以具体支持到什么版本没有测试,但是一般而言,国内使用这些浏览器的用户都会选择较新的版本,应该没有问题)。

  2. 测试页面编写

  测试页面有内嵌的CSS元素,以及引入的Javascript代码,即getOffset函数。测试页面有以下几个元素需要注意,首先就是id为target的元素,它是我们要获取绝对坐标的元素,它存在一个div元素中,这个div元素随着测试的进行,它的position是否为静态,是否又边框,是否又滚动条会发生变化,从而测试我们函数的健壮性。每次测试的触发都是通过对id为button的元素单击完成的,测试完成后,需要一个小元素去证明获取的是否正确,即id为testResult的元素。id为coord元素也只是起一个坐标指示的作用,您可以忽略它。下面是html文件最终的测试版本,您如果用该文件进行测试,在接下来的每一小节的描述中,您需要自行修改CSS部分。



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
    <title>测试最完整的获取页面Dom元素的绝对位置的函数-Get Absolute Positon of DOM Element by Javascript </title>
    <script type="text/javascript" src="getOffset.js"></script>
    <style type="text/css">
        html, body {
            margin: 0;
            padding: 0;
        }

        html {

        }

        body {
            min-height: 1200px;
            border: 10px solid red;    
            margin: 30px;
        }
    
        .wrap1 {
            background-color: #777;
        }
        .wrap2 {
            background-color: #999;
            margin-left: 20px;
        }
        .wrap3 {
            background-color: #BBB;
            margin-left: 20px;
            padding-left: 10px;
            height: 400px;
            width: 400px;
        }
        .pos-static {
            position: static;
        }
        .pos-nonstatic {
            position: relative;
            left: 50px;
            top: 10px;
        }
        .bd {
            border: 10px solid yellow;
        }
        .non-bd {
            border:none;
        }
        .scrl {
            overflow: scroll;
            height: 200px;
        }

        .non-scrl {
            overflow: auto;
        }
        #target {
            background: blue;
        }
        #testResult {
            width: 10px;
            height: 10px;
            position:absolute;
            background-color:green;
            left:0px;
            top:0px;
            z-index: 100;
        }

        #coord {
            width: 10px;
            height: 210px;
            position: absolute;
            left: 200px;
            top:0px;
            background: green;
            z-index: 400;
        }
        #seperator {
            height: 200px;
            background: white;
        }

    </style>
</head>
<body>
    <div id="testResult"></div>
    <div id="coord"></div>
    <div class="wrap1">
        <div class="wrap2 pos-nonstatic">
            <div class="wrap3 bd scrl">
                <div id="seperator">                    
                </div>
                <div id="target">My position</div>
            </div>
        </div>
        <h1>--------------------------------------------------</h1>        
    </div>
    <div id="button" style="border:1px solid;">计算 | getOffset_geetest</div>
    <div id="result">
        
    </div>
    <script type="text/javascript">
        var button = document.getElementById('button');
        var target = document.getElementById('target');
        var result = document.getElementById('result');
        var testResult = document.getElementById('testResult');

        button.onclick = function () {            
            var str = ('Ele属性: offsetLeft:' + target.offsetLeft + ' offsetTop:' +target.offsetTop +  ' scrollLeft:' + target.scrollLeft + ' scrollTop:' +target.scrollTop + '<br />');
            var pos = getOffset_geetest_ex(target);
            str += ('getOffset:' + pos.left + ', ' + pos.top +'<br />');        
            result.innerHTML = str;

            testResult.style.left = pos.left + "px";
            testResult.style.top = pos.top + "px";
        }
    </script>
</body>
</html>



3. 最原始的getOffset函数,直接用offsetTop 和 offsetLeft递


function getOffset(el) {
    var _x = 0, _y = 0;
    while (el && !isNaN(el.offsetLeft) && !isNaN(el.offsetTop)) {
        _x += el.offsetLeft - el.scrollLeft;
        _y += el.offsetTop - el.scrollTop;
        el = el.offsetParent;
    }
    return { top: _y, left: _x };
}

 

4. 测试第一步,target的父元素有边框外,无滚动,body有边框,border为10,且body的position为relative。

可以看到初始情况下,用于测试结果的testResult小方块正好在body的框内。如下图所示

JavaScript 获得元素name javascript获取元素的方法_xhtml

测试结果如下所示:


offsetTop

最终的top

offsetLeft

最终的left

偏移

Chrome

220

210

70

60

Firefox

210

210

60

60

Opera

220

210

70

60

IE(高)

210

210

60

60

IE(低)

200

210

10

60

  通过上表可以看出,Opera和Chrome浏览器的表现很一致,即他们的offsetLeft和offsetTop包含了body元素的边框大小,而Firefox和ie则没有包含。ie低版本是因为它的offsetLeft指向了它的父元素(position为static)。如果此时,设置body元素的margin,padding都没有任何影响。

(待续...)