用JavaScript获取DOM元素位置和尺寸大小的方法


Posted in Javascript onApril 12, 2013

在一些复杂的页面中经常会用JavaScript处理一些DOM元素的动态效果,这种时候我们经常会用到一些元素位置和尺寸的计算,浏览器兼容性问题也是不可忽略的一部分,要想写出预想效果的JavaScript代码,我们需要了解一些基本知识。

基础概念

为了方便理解,我们需要了解几个基础概念,每个HTML元素都有下列属性

offsetWidth clientWidth scrollWidth
offsetHeight clientHeight scrollHeight
offsetLeft clientLeft scrollLeft
offsetTop clientTop scrollTop

为了理解这些属性,我们需要知道HTML元素的实际内容有可能比分配用来容纳内容的盒子更大,因此可能会出现滚动条,内容区域是视口,当实际内容比视口大的时候,需要把元素的滚动条位置考虑进去。

1. clientHeight和clientWidth用于描述元素内尺寸,是指 元素内容+内边距 大小,不包括边框(IE下实际包括)、外边距、滚动条部分

2. offsetHeight和offsetWidth用于描述元素外尺寸,是指 元素内容+内边距+边框,不包括外边距和滚动条部分

3. clientTop和clientLeft返回内边距的边缘和边框的外边缘之间的水平和垂直距离,也就是左,上边框宽度

4. offsetTop和offsetLeft表示该元素的左上角(边框外边缘)与已定位的父容器(offsetParent对象)左上角的距离

5. offsetParent对象是指元素最近的定位(relative,absolute)祖先元素,递归上溯,如果没有祖先元素是定位的话,会返回null

写个小例子方便理解

<div id="divParent" style="padding: 8px; background-color: #aaa; position: relative;">
        <div id="divDisplay" style="background-color: #0f0; margin: 30px; padding: 10px;
            height: 200px; width: 200px; border: solid 3px #f00;">
        </div>
    </div>

<script type="text/javascript">
        var div = document.getElementById('divDisplay');
        var clientHeight = div.clientHeight;
        var clientWidth = div.clientWidth;
        div.innerHTML += 'clientHeight: ' + clientHeight + '<br/>';
        div.innerHTML += 'clientWidth: ' + clientWidth + '<br/>';
        var clientLeft = div.clientLeft;
        var clientTop = div.clientTop;
        div.innerHTML += 'clientLeft: ' + clientLeft + '<br/>';
        div.innerHTML += 'clientTop: ' + clientTop + '<br/>';
        var offsetHeight = div.offsetHeight;
        var offsetWidth = div.offsetWidth;
        div.innerHTML += 'offsetHeight: ' + offsetHeight + '<br/>';
        div.innerHTML += 'offsetWidth: ' + offsetWidth + '<br/>';
        var offsetLeft = div.offsetLeft;
        var offsetTop = div.offsetTop;
        div.innerHTML += 'offsetLeft: ' + offsetLeft + '<br/>';
        div.innerHTML += 'offsetTop: ' + offsetTop + '<br/>';
        var offsetParent = div.offsetParent;
        div.innerHTML += 'offsetParent: ' + offsetParent.id + '<br/>';
    </script>

效果如图

用JavaScript获取DOM元素位置和尺寸大小的方法

从图中我们可以看到,clientHeight就是div的高度+上下各10px的padding,clientWidth同理

而clientLeft和ClientTop即为div左、上边框宽度

offsetHeight是clientHeight+上下个3px的边框宽度之和,offsetWidth同理

offsetTop是div 30px的 maggin+offsetparent 8px的 padding,offsetLeft同理

 

6. scrollWidth和scrollHeight是元素的内容区域加上内边距加上溢出尺寸,当内容正好和内容区域匹配没有溢出时,这些属性与clientWidth和clientHeight相等

7. scrollLeft和scrollTop是指元素滚动条位置,它们是可写的

下面写个简单例子理解

<div id="divParent" style="background-color: #aaa; padding:8px; border:solid 7px #000; height:200px; width:500px; overflow:auto;">
        <div id="divDisplay" style="background-color: #0f0; margin: 30px; padding: 10px;
            height: 400px; width: 200px; border: solid 3px #f00;">
        </div>
    </div>

<script type="text/javascript">
        var divP = document.getElementById('divParent');
        var divD = document.getElementById('divDisplay');
        var scrollHeight = divP.scrollHeight;
        var scrollWidth = divP.scrollWidth;
        divD.innerHTML += 'scrollHeight: ' + scrollHeight + '<br/>';
        divD.innerHTML += 'scrollWidth: ' + scrollWidth + '<br/>';
    </script>

在FireFox和IE10(IE10以下版本盒模型和W3C标准不一致,不加讨论,兼容性问题下面会介绍到)下得到结果scrollHeight: 494,而在Chrome和Safari下得到结果scrollHeight: 502,差了8px,根据8可以简单推测是divParent的padding,来算一下是不是

我们可以看看它们的结果是怎么来的,首先scrollHeight肯定包含了divDisplay所需的高度 400px的高度+上下各10px的padding+上下各3px的border+上下各30px的margin,这样

400+10*2+3*2+30*2=486

这样486+8=494, 486+8*2=502果真是这样,在FireFox和IE10下没有计算下padding

有了这些基础知识后,我们就可以计算元素的位置和尺寸了。

相对于文档与视口的坐标

当我们计算一个DOM元素位置也就是坐标的时候,会涉及到两种坐标系,文档坐标和视口坐标。

我们经常用到的document就是整个页面部分,而不仅仅是窗口可见部分,还包括因为窗口大小限制而出现滚动条的部分,它的左上角就是我们所谓相对于文档坐标的原点。

视口是显示文档内容的浏览器的一部分,它不包括浏览器外壳(菜单,工具栏,状态栏等),也就是当前窗口显示页面部分,不包括滚动条。

如果文档比视口小,说明没有出现滚动,文档左上角和视口左上角相同,一般来讲在两种坐标系之间进行切换,需要加上或减去滚动的偏移量(scroll offset)。

为了在坐标系之间进行转换,我们需要判定浏览器窗口的滚动条位置。window对象的pageXoffset和pageYoffset提供这些值,IE 8及更早版本除外。也可以通过scrollLeft和scrollTop属性获得滚动条位置,正常情况下通过查询文档根节点(document.documentElement)来获得这些属性值,但在怪异模式下必须通过文档的body上查询。

function getScrollOffsets(w) {
            var w = w || window;
            if (w.pageXoffset != null) {
                return { x: w.pageXoffset, y: pageYoffset };
            }
            var d = w.document;
            if (document.compatMode == "CSS1Compat")
                return { x: d.documentElement.scrollLeft, y: d.documentElement.scrollTop };
            return { x: d.body.scrollLeft, y: d.body.scrollTop };
        }

有时候能够判断视口的尺寸也是非常有用的
function getViewPortSize(w) {
            var w = w || window;
            if (w.innerWidth != null)
                return { w: w.innerWidth, h: w.innerHeight };
            var d = w.document;
            if (document.compatMode == "CSS1Compat")
                return { w: d.documentElement.clientWidth, h: d.documentElement.clientHeight };
            return { w: d.body.clientWidth, h: d.body.clientHeight };
        }

文档坐标

任何HTML元素都拥有offectLeft和offectTop属性返回元素的X和Y坐标,对于很多元素,这些值是文档坐标,但是对于以定位元素后代及一些其他元素(表格单元),返回相对于祖先的坐标。我们可以通过简单的递归上溯累加计算

function getElementPosition(e) {
            var x = 0, y = 0;
            while (e != null) {
                x += e.offsetLeft;
                y += e, offsetTop;
                e = e.offsetParent;
            }
            return { x: x, y: y };
        }

尽管如此,这个函数也不总是计算正确的值,当文档中含有滚动条的时候这个方法就不能正常工作了,我们只能在没有滚动条的情况下使用这个方法,不过我们用这个原理算出一些元素相对于某个父元素的坐标。

视口坐标

计算视口坐标就相对简单了很多,可以通过调用元素的getBoundingClientRect方法。方法返回一个有left、right、top、bottom属性的对象,分别表示元素四个位置的相对于视口的坐标。getBoundingClientRect所返回的坐标包含元素的内边距和边框,不包含外边距。兼容性很好,非常好用

元素尺寸

由上面计算坐标方法,我们可以方便得出元素尺寸。在符合W3C标准的浏览器中getBoundingClientRect返回的对象还包括width和height,但在原始IE中未实现,但是通过返回对象的right-left和bottom-top可以方便计算出。

Javascript 相关文章推荐
javascript引用对象的方法
Jan 11 Javascript
Javascript 代码也可以变得优美的实现方法
Jun 22 Javascript
使用Post提交时须将空格转换成加号的解释
Jan 14 Javascript
Jquery中国地图热点效果-鼠标经过弹出提示层信息的简单实例
Feb 12 Javascript
一个不错的字符串转码解码函数(自写)
Jul 31 Javascript
javascript中call,apply,bind的用法对比分析
Feb 12 Javascript
JS实现图片放大镜效果的方法
Feb 27 Javascript
JS实现弹出浮动窗口(支持鼠标拖动和关闭)实例详解
Aug 06 Javascript
javascript实现别踩白块儿小游戏程序
Nov 22 Javascript
学习Node.js模块机制
Oct 17 Javascript
jQuery通过改变input的type属性实现密码显示隐藏切换功能
Feb 08 Javascript
js实现音频控制进度条功能
Apr 01 Javascript
深入理解JavaScript 闭包究竟是什么
Apr 12 #Javascript
关于JavaScript中string 的replace
Apr 12 #Javascript
关于JavaScript与HTML的交互事件
Apr 12 #Javascript
Js中setTimeout()和setInterval() 何时被调用执行的用法
Apr 12 #Javascript
js实现单一html页面两套css切换代码
Apr 11 #Javascript
获取内联和链接中的样式(js代码)
Apr 11 #Javascript
JavaScript在XHTML中的用法详解
Apr 11 #Javascript
You might like
图形数字验证代码
2006/10/09 PHP
Zend Framework教程之请求对象的封装Zend_Controller_Request实例详解
2016/03/07 PHP
Laravel框架Eloquent ORM简介、模型建立及查询数据操作详解
2019/12/04 PHP
Cookie 小记
2010/04/01 Javascript
Javascript对象中关于setTimeout和setInterval的this介绍
2012/07/21 Javascript
原生js实现改变随意改变div属性style的名称和值的结果
2013/09/26 Javascript
JavaScript获取function所有参数名的方法
2015/10/30 Javascript
使用Sticky组件实现带sticky效果的tab导航和滚动导航的方法
2016/03/22 Javascript
Bootstrap Table的使用总结
2016/10/08 Javascript
nodejs集成sqlite使用示例
2017/06/05 NodeJs
js实现上传并压缩图片效果
2018/01/10 Javascript
Javascript实现购物车功能的详细代码
2018/05/08 Javascript
js中实例与对象的区别讲解
2019/01/21 Javascript
关于layui的下拉搜索框异步加载数据的解决方法
2019/09/28 Javascript
详解Vue之事件处理
2020/07/10 Javascript
Postman如何实现参数化执行及断言处理
2020/07/28 Javascript
教你用Python脚本快速为iOS10生成图标和截屏
2016/09/22 Python
Python2实现的图片文本识别功能详解
2018/07/11 Python
浅谈pytorch和Numpy的区别以及相互转换方法
2018/07/26 Python
Python面向对象基础入门之编码细节与注意事项
2018/12/11 Python
详解Django CAS 解决方案
2019/10/30 Python
如何在mac下配置python虚拟环境
2020/07/06 Python
django 将自带的数据库sqlite3改成mysql实例
2020/07/09 Python
Python测试框架:pytest学习笔记
2020/10/20 Python
RetroStage德国:复古服装
2019/02/03 全球购物
毕业生自我鉴定范文
2013/11/08 职场文书
会计应届生的自荐信
2013/12/13 职场文书
护士毕业自我鉴定
2014/02/07 职场文书
大学生村官承诺书
2014/03/28 职场文书
初中学生评语大全
2014/04/24 职场文书
个人主要事迹材料
2014/08/26 职场文书
综合管理员岗位职责
2015/02/11 职场文书
2016党性教育学习心得体会
2016/01/21 职场文书
关于JavaScript轮播图的实现
2021/11/20 Javascript
使用SQL实现车流量的计算的示例代码
2022/02/28 SQL Server
Python使用OpenCV实现虚拟缩放效果
2022/02/28 Python