1.通过遍历目标节点、目标节点的父节点,依次溯源。
然后累加这些节点到其最近可定位的祖先节点的距离。向上直到document。
其中,需要使用到节点的offsetTop/offsetLeft属性,来获取节点到最近祖先元素的距离。(position不为static)
需要使用到getComputedStyle来获取节点的计算属性。
代码实现:
function fn(ele) { let result = { left: 0, top: 0 } // 节点display为none时,直接返回 if (window.getComputedStyle(ele).display === 'none') return; function getOffset(node, init) { // 节点类型 if (node.nodeType !== 1) return; // 定位属性值 const position = window.getComputedStyle(node).position; // 目标节点跳过该判断 if (init !== true && position === 'static') { getOffset(node.parentNode); return; } result.top += node.offsetTop - node.scrollTop; result.left += node.offsetLeft - node.scrollLeft; // 目标节点为绝对定位,无需递归操作,直接返回 if (position === 'fixed') return; getOffset(node.parentNode); } getOffset(ele, true); return result; }
上述代码通过递归实现,当节点类型不等于1时,返回。
当节点position为static时,不进行计算,传入父节点进行递归操作。
当目标节点隐藏时,直接返回0。
2.通过getBoundingClientRect()方法
该方法
代码实现:
function fn(ele) { let result = { top: 0, left: 0 }; if (window.getComputedStyle(ele).display === 'none') return; const docEl = document.documentElement; // 存在该方法时 if (docEl.getBoundingClientRect) { result = ele.getBoundingClientRect() return { left: result.left + docEl.scrollLeft - docEl.clientLeft, top: result.top + docEl.scrollTop - docEl.clientTop } } return result; }
其中scrollLeft/scrollTop为窗口的水平垂直的滚动距离。
clientLeft/clientTop为元素边框的宽度。