用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中2个感叹号的用法实例详解
Sep 04 Javascript
JavaScript实现带标题的图片轮播特效
May 20 Javascript
基于JS实现的倒计时程序实例
Jul 24 Javascript
js 监控iframe URL的变化实例代码
Jul 12 Javascript
微信小程序出现wx.navigateTo页面不跳转问题的解决方法
Dec 26 Javascript
脚手架vue-cli工程webpack的作用和特点
Sep 29 Javascript
angular学习之动态创建表单的方法
Dec 07 Javascript
Egg Vue SSR 服务端渲染数据请求与asyncData
Nov 24 Javascript
javascript使用Blob对象实现的下载文件操作示例
Apr 18 Javascript
解决vue项目,npm run build后,报路径错的问题
Aug 13 Javascript
OpenLayers3实现地图显示功能
Sep 25 Javascript
Vue中父子组件的值传递与方法传递
Sep 28 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
php函数之子字符串替换&amp;#65279; str_replace
2011/03/23 PHP
探讨多键值cookie(php中cookie存取数组)的详解
2013/06/06 PHP
PHP获取POST数据的几种方法汇总
2015/03/03 PHP
php判断邮箱地址是否存在的方法
2016/02/13 PHP
PHP实现广度优先搜索算法(BFS,Broad First Search)详解
2017/09/16 PHP
JavaScript 页面编码与浏览器类型判断代码
2010/06/03 Javascript
jQuery队列控制方法详解queue()/dequeue()/clearQueue()
2010/12/02 Javascript
JavaScript高级程序设计(第3版)学习笔记4 js运算符和操作符
2012/10/11 Javascript
js中switch case循环实例代码
2013/12/30 Javascript
用javascript替换URL中的参数值示例代码
2014/01/27 Javascript
js 实现浏览历史记录示例
2014/04/20 Javascript
js调试工具console.log()方法查看js代码的执行情况
2014/08/08 Javascript
让人蛋疼的JavaScript语法特性
2014/09/30 Javascript
JS 动态加载js文件和css文件 同步/异步的两种简单方式
2016/09/23 Javascript
Javascript 跨域知识详细介绍
2016/10/30 Javascript
Bootstrap框架安装使用详解
2017/01/21 Javascript
老生常谈jquery id选择器和class选择器的区别
2017/02/12 Javascript
原生JS实现图片网格式渐显、渐隐效果
2017/06/05 Javascript
Angular6使用forRoot() 注册单一实例服务问题
2019/08/27 Javascript
JS中准确判断变量类型的方法
2020/06/01 Javascript
ubuntu中配置pyqt4环境教程
2017/12/27 Python
python+matplotlib演示电偶极子实例代码
2018/01/12 Python
python之文件读取一行一行的方法
2018/07/12 Python
python 实现创建文件夹和创建日志文件的方法
2019/07/07 Python
18个Python脚本可加速你的编码速度(提示和技巧)
2019/10/17 Python
美国领先的水果篮送货公司和新鲜水果供应商:The Fruit Company
2018/02/13 全球购物
机电一体化专业应届本科生求职信
2013/09/27 职场文书
机械电子工程专业推荐信范文
2013/11/20 职场文书
高中自我评价分享
2013/12/05 职场文书
秋季运动会稿件
2014/01/30 职场文书
大学生预备党员自我评价
2015/03/04 职场文书
保外就医申请书范文
2015/08/06 职场文书
详解CSS伪元素的妙用单标签之美
2021/05/25 HTML / CSS
SQL SERVER存储过程用法详解
2022/02/24 SQL Server
python神经网络Xception模型
2022/05/06 Python
MySQL运行报错:“Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggre”解决方法
2022/06/14 MySQL