正确设置绝对定位的dom元素的位置

JIN Weijie
JIN Weijie
Published in
3 min readAug 20, 2009

先前在做ASTreeView右键菜单时遇到一个问题,是这样的:

因为页面的布局中,放置ASTreeView控件的容器叫container,当用户右键点击树节点时,edit, delete节点的菜单出现。由于container的position是relative的,右键菜单的div的position是absolute的,所以,设置菜单div的left, top属性时,会根据container的位置去定位,如图所示:

image

当用户点击右键,我们可以获取当前鼠标的坐标,这时,如果直接将鼠标的x,y坐标赋值给菜单的left和top就会出问题。因为鼠标坐标的原点是窗口的左上角,而菜单的原点是container的左上角。

那如何让菜单显示在鼠标点击的位置呢?接下来的代码将一步一步地实现:

首先是获取鼠标坐标的代码:

function getMousePos(e) {e = e || event;var posx = 0;
var posy = 0;
if ( e.pageX && e.pageY ) {
posx = e.pageX;
posy = e.pageY;
}
else if (e.clientX && e.clientY ) {
posx = e.clientX + document.body.scrollLeft
+ document.documentElement.scrollLeft;
posy = e.clientY + document.body.scrollTop
+ document.documentElement.scrollTop;
}
return {
'x' : posx,
'y' : posy
}
}

接着我们将要得到container相对于窗口左上角的距离,当然,这要考虑container的父节点,也就是要一直递归到根节点:

function getTotalOffset( elem ){
var offsetTotalX = 0;
var offsetTotalY = 0;
var pOffsetElem = elem.offsetParent;
while( pOffsetElem ){
offsetTotalX += pOffsetElem.offsetLeft;
offsetTotalY += pOffsetElem.offsetTop;
pOffsetElem = pOffsetElem.offsetParent;
}
return {
'x' : offsetTotalX,
'y' : offsetTotalY
}
}

最后在设置菜单位置的时候,将鼠标的位置,减去container的offset:

var pos = getMousePos(e);
var offset = getTotalOffset(elem);
menu.style.left = ( pos.x - offset.x ) + 'px';
menu.style.top = ( pos.y - offset.y ) + 'px';

这样,菜单就能显示在鼠标点击的位置啦!

完整示例下载:

点击下载

--

--

JIN Weijie
JIN Weijie

Maximizing Quality of Life, Being Earth Friendly.