获取DOM元素的绝对位置

在Web开发中,经常需要获取某个DOM元素在文档中的绝对位置。例如,可能希望在某个文本标签下方显示一个弹出菜单,这时就需要知道该标签的确切位置。本文将介绍如何实现这一功能,并考虑不同浏览器的兼容性问题。

解决方案

要获取元素在其父元素中的位置,可以使用style.leftstyle.topoffsetLeftoffsetTop等属性。但是,要获取元素在文档中的绝对位置,需要沿着元素树向上遍历,并累加所有父元素的位置(除了最后一个document元素)。

这个过程并不简单,因为需要考虑以下几个问题:

  • 需要考虑元素父元素的滚动条位置,并相应地减少结果。
  • 不同浏览器的行为存在差异。例如,在Internet Explorer中,只需要减去元素的offsetParent属性中存储的滚动位置。但在Firefox中,还需要考虑所有可以通过parentNode属性访问的父元素。
  • 需要考虑某些父元素的边框宽度。遗憾的是,这项任务并不像想象的那么简单,尤其是在Internet Explorer中。

实现函数

以下是实现的函数:

function __getIEVersion() { var rv = -1; if (navigator.appName == 'Microsoft Internet Explorer') { var ua = navigator.userAgent; var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})"); if (re.exec(ua) != null) rv = parseFloat(RegExp.$1); } return rv; } function __getOperaVersion() { var rv = 0; if (window.opera) { var sver = window.opera.version(); rv = parseFloat(sver); } return rv; } var __userAgent = navigator.userAgent; var __isIE = navigator.appVersion.match(/MSIE/) != null; var __IEVersion = __getIEVersion(); var __isIENew = __isIE && __IEVersion >= 8; var __isIEOld = __isIE && !__isIENew; var __isFireFox = __userAgent.match(/firefox/i) != null; var __isFireFoxOld = __isFireFox && ((__userAgent.match(/firefox\/2./i) != null) || (__userAgent.match(/firefox\/1./i) != null)); var __isFireFoxNew = __isFireFox && !__isFireFoxOld; var __isWebKit = navigator.appVersion.match(/WebKit/) != null; var __isChrome = navigator.appVersion.match(/Chrome/) != null; var __isOpera = window.opera != null; var __operaVersion = __getOperaVersion(); var __isOperaOld = __isOpera && (__operaVersion < 10); function __parseBorderWidth(width) { var res = 0; if (typeof(width) == "string" && width != null && width != "") { var p = width.indexOf("px"); if (p >= 0) { res = parseInt(width.substring(0, p)); } else { res = 1; } } return res; } function __getBorderWidth(element) { var res = new Object(); res.left = 0; res.top = 0; res.right = 0; res.bottom = 0; if (window.getComputedStyle) { var elStyle = window.getComputedStyle(element, null); res.left = parseInt(elStyle.borderLeftWidth.slice(0, -2)); res.top = parseInt(elStyle.borderTopWidth.slice(0, -2)); res.right = parseInt(elStyle.borderRightWidth.slice(0, -2)); res.bottom = parseInt(elStyle.borderBottomWidth.slice(0, -2)); } else { res.left = __parseBorderWidth(element.style.borderLeftWidth); res.top = __parseBorderWidth(element.style.borderTopWidth); res.right = __parseBorderWidth(element.style.borderRightWidth); res.bottom = __parseBorderWidth(element.style.borderBottomWidth); } return res; } function getElementAbsolutePos(element) { var res = new Object(); res.x = 0; res.y = 0; if (element !== null) { if (element.getBoundingClientRect) { var viewportElement = document.documentElement; var box = element.getBoundingClientRect(); var scrollLeft = viewportElement.scrollLeft; var scrollTop = viewportElement.scrollTop; res.x = box.left + scrollLeft; res.y = box.top + scrollTop; } else { res.x = element.offsetLeft; res.y = element.offsetTop; var parentNode = element.parentNode; var borderWidth = null; while (offsetParent != null) { res.x += offsetParent.offsetLeft; res.y += offsetParent.offsetTop; var parentTagName = offsetParent.tagName.toLowerCase(); if ((__isIEOld && parentTagName != "table") || ((__isFireFoxNew || __isChrome) && parentTagName == "td")) { borderWidth = __getBorderWidth(offsetParent); res.x += borderWidth.left; res.y += borderWidth.top; } if (offsetParent != document.body && offsetParent != document.documentElement) { res.x -= offsetParent.scrollLeft; res.y -= offsetParent.scrollTop; } if (!__isIE && !__isOperaOld || __isIENew) { while (offsetParent != parentNode && parentNode !== null) { res.x -= parentNode.scrollLeft; res.y -= parentNode.scrollTop; if (__isFireFoxOld || __isWebKit) { borderWidth = __getBorderWidth(parentNode); res.x += borderWidth.left; res.y += borderWidth.top; } parentNode = parentNode.parentNode; } } parentNode = offsetParent.parentNode; offsetParent = offsetParent.offsetParent; } } } return res; }

使用函数

var pos = getElementAbsolutePos(myElement); window.alert("Element's left: " + pos.x + " and top: " + pos.y);
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485