深入分析获取元素坐标的三种方法的不同地方
说坐标就要考虑参考点,首先要理解获取元素坐标是以文档(html元素)的左上角为参考点,不是浏览器左上角
案例分析
<div id="testid" style="border:solid 10px red; width:400px; height:200px; position:relative; overflow:auto; ">
testid
<div id="testid1" style="border:solid 5px green; position:absolute; width:200px; height:300px; top:70px; left:100px ">
testid1
</div>
</div>
<input type="button" value="点击案例1" onclick="eyejsTest('testid1')" />
<input type="button" value="点击案例2" onclick="eyejsTest2('testid1')" />
<input type="button" value="点击案例3" onclick="eyejsTest3('testid1')" />
----------------------------------------
第一种方法eyejsGetNode1,是很常用的方法,可这种写法在某些情况下是不对的
准确地说只能应用在该元素和所有的父级节点不能有边框和滚动,否则获取到的坐标就是不正确的
必需准确地理解offsetTop和offsetLeft, 以offsetTop为例,offsetTop是本元素的外侧到直接父级的内侧的距离(如果有滚动部分,包括滚动部分)
请看详解offsetTop,offsetLeft,offsetParent并给于案例
<script type="text/javascript">
function $(id){return document.getElementById(id);}
var eyejsGetNode1=function(id){
var obj=$(id);
var pos =[];
pos =[obj.offsetLeft,obj.offsetTop];//
var parent = obj.offsetParent;
while(parent){
pos[0] += parent.offsetLeft;
pos[1] += parent.offsetTop;
parent=parent.offsetParent;
}
return {x:pos[0],y:pos[1]};
}
var eyejsTest=function(id){
var node=eyejsGetNode1(id);
alert("Y坐标"+node.y);
}
</script>
点击弹出元素的坐标,再滚动后,再点击弹出元素的坐标
可以发现:该元素的已经发现变化坐标, 可计算结果并没有变化,(应该减去滚动部分)
<div style="margin-top:20px; border-top:solid 1px red; width:500px;">案例二</div>
<script type="text/javascript">
/*方法二:弥补方法一的缺点 加上边框部分和除去元素滚动部分,但不能除去body滚动部分*/
var $ = function (id) {return "string" == typeof id ? document.getElementById(id) : id;};
var isIE = (document.all) ? true : false;
if(!isIE){
HTMLElement.prototype.__defineGetter__("currentStyle", function () {
return this.ownerDocument.defaultView.getComputedStyle(this, null);
});
}
var eyejsGetNode2=function(id){
var obj=$(id);
var x=0,y=0;
var scrollX=0,scrollY=0;
if(obj.offsetParent){
if( obj.offsetParent.tagName.toLowerCase()!="body"&&obj.offsetParent.tagName.toLowerCase()!="html" ){
scrollX=obj.offsetParent.scrollLeft;
scrollY=obj.offsetParent.scrollTop;
//去掉元素滚动部分,但是不能除掉html或body的滚动部分,理解obj.offsetParent的指向哪个元素,最顶级的父级元素是IE是HTMLhtmlElement而
//FF是HTMLbodyElement 因此要这样判断
}
}
x+=obj.offsetLeft-scrollX;
y+=obj.offsetTop-scrollY;
while(obj=obj.offsetParent){
scrollX=0;scrollY=0;
var borderLeftWidth=0;
var borderTopWidth=0;
if(obj.tagName.toLowerCase()!="body"||obj.tagName.toLowerCase()!="html"){
borderLeftWidth=!isNaN(parseInt(obj.currentStyle.borderLeftWidth))?parseInt(obj.currentStyle.borderLeftWidth):0;
borderTopWidth=!isNaN(parseInt(obj.currentStyle.borderTopWidth))?parseInt(obj.currentStyle.borderTopWidth):0;
}
if(obj.offsetParent){
if( obj.offsetParent.tagName.toLowerCase()!="body"&&obj.offsetParent.tagName.toLowerCase()!="html" ){
scrollX=obj.offsetParent.scrollLeft;
scrollY=obj.offsetParent.scrollTop;
}
}
//alert(obj.offsetParent);
x+=obj.offsetLeft+borderLeftWidth-scrollX;
y+=obj.offsetTop+borderTopWidth-scrollY;
if(obj.tagName.toLowerCase()=="html")
break;
}
return {"x":x,"y":y};
}
var eyejsTest2=function(id){
var node=eyejsGetNode2(id);
alert("Y坐标"+node.y);
}
</script>
<div>
点击弹出元素的坐标,再滚动后,再点击弹出元素的坐标
可以发现:该元素的已经发现变化坐标, 计算结果也着随变化
但是你如果先放在IE下测试,再放在FF测试你会发现结果不一样
为什么呢?去掉ID为testid的元素的边框样式,再试试,会发现结果一样了
<div>
</div>
----
案例三:
利用浏览器内置的获取元素坐标函数getBoundingClientRect
//此方法在IE和Firefox/3.0.12版本下通过
<script type="text/javascript">
var eyejsGetNode3=function(id){
var el=$(id);
var pos =[];
var box=null;
if(el.getBoundingClientRect){
box = el.getBoundingClientRect();
var scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
var scrollLeft = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
return {x:box.left + scrollLeft, y:box.top + scrollTop}; //
}
return {x:0,y:0};
}
var eyejsTest3=function(id){
var node=eyejsGetNode3(id);
alert("Y坐标"+node.y);
}
</script>
案例下载地址: http://www.eyejs.com/html/66/n-166.html
案例分析
<div id="testid" style="border:solid 10px red; width:400px; height:200px; position:relative; overflow:auto; ">
testid
<div id="testid1" style="border:solid 5px green; position:absolute; width:200px; height:300px; top:70px; left:100px ">
testid1
</div>
</div>
<input type="button" value="点击案例1" onclick="eyejsTest('testid1')" />
<input type="button" value="点击案例2" onclick="eyejsTest2('testid1')" />
<input type="button" value="点击案例3" onclick="eyejsTest3('testid1')" />
----------------------------------------
第一种方法eyejsGetNode1,是很常用的方法,可这种写法在某些情况下是不对的
准确地说只能应用在该元素和所有的父级节点不能有边框和滚动,否则获取到的坐标就是不正确的
必需准确地理解offsetTop和offsetLeft, 以offsetTop为例,offsetTop是本元素的外侧到直接父级的内侧的距离(如果有滚动部分,包括滚动部分)
请看详解offsetTop,offsetLeft,offsetParent并给于案例
<script type="text/javascript">
function $(id){return document.getElementById(id);}
var eyejsGetNode1=function(id){
var obj=$(id);
var pos =[];
pos =[obj.offsetLeft,obj.offsetTop];//
var parent = obj.offsetParent;
while(parent){
pos[0] += parent.offsetLeft;
pos[1] += parent.offsetTop;
parent=parent.offsetParent;
}
return {x:pos[0],y:pos[1]};
}
var eyejsTest=function(id){
var node=eyejsGetNode1(id);
alert("Y坐标"+node.y);
}
</script>
点击弹出元素的坐标,再滚动后,再点击弹出元素的坐标
可以发现:该元素的已经发现变化坐标, 可计算结果并没有变化,(应该减去滚动部分)
<div style="margin-top:20px; border-top:solid 1px red; width:500px;">案例二</div>
<script type="text/javascript">
/*方法二:弥补方法一的缺点 加上边框部分和除去元素滚动部分,但不能除去body滚动部分*/
var $ = function (id) {return "string" == typeof id ? document.getElementById(id) : id;};
var isIE = (document.all) ? true : false;
if(!isIE){
HTMLElement.prototype.__defineGetter__("currentStyle", function () {
return this.ownerDocument.defaultView.getComputedStyle(this, null);
});
}
var eyejsGetNode2=function(id){
var obj=$(id);
var x=0,y=0;
var scrollX=0,scrollY=0;
if(obj.offsetParent){
if( obj.offsetParent.tagName.toLowerCase()!="body"&&obj.offsetParent.tagName.toLowerCase()!="html" ){
scrollX=obj.offsetParent.scrollLeft;
scrollY=obj.offsetParent.scrollTop;
//去掉元素滚动部分,但是不能除掉html或body的滚动部分,理解obj.offsetParent的指向哪个元素,最顶级的父级元素是IE是HTMLhtmlElement而
//FF是HTMLbodyElement 因此要这样判断
}
}
x+=obj.offsetLeft-scrollX;
y+=obj.offsetTop-scrollY;
while(obj=obj.offsetParent){
scrollX=0;scrollY=0;
var borderLeftWidth=0;
var borderTopWidth=0;
if(obj.tagName.toLowerCase()!="body"||obj.tagName.toLowerCase()!="html"){
borderLeftWidth=!isNaN(parseInt(obj.currentStyle.borderLeftWidth))?parseInt(obj.currentStyle.borderLeftWidth):0;
borderTopWidth=!isNaN(parseInt(obj.currentStyle.borderTopWidth))?parseInt(obj.currentStyle.borderTopWidth):0;
}
if(obj.offsetParent){
if( obj.offsetParent.tagName.toLowerCase()!="body"&&obj.offsetParent.tagName.toLowerCase()!="html" ){
scrollX=obj.offsetParent.scrollLeft;
scrollY=obj.offsetParent.scrollTop;
}
}
//alert(obj.offsetParent);
x+=obj.offsetLeft+borderLeftWidth-scrollX;
y+=obj.offsetTop+borderTopWidth-scrollY;
if(obj.tagName.toLowerCase()=="html")
break;
}
return {"x":x,"y":y};
}
var eyejsTest2=function(id){
var node=eyejsGetNode2(id);
alert("Y坐标"+node.y);
}
</script>
<div>
点击弹出元素的坐标,再滚动后,再点击弹出元素的坐标
可以发现:该元素的已经发现变化坐标, 计算结果也着随变化
但是你如果先放在IE下测试,再放在FF测试你会发现结果不一样
为什么呢?去掉ID为testid的元素的边框样式,再试试,会发现结果一样了
<div>
</div>
----
案例三:
利用浏览器内置的获取元素坐标函数getBoundingClientRect
//此方法在IE和Firefox/3.0.12版本下通过
<script type="text/javascript">
var eyejsGetNode3=function(id){
var el=$(id);
var pos =[];
var box=null;
if(el.getBoundingClientRect){
box = el.getBoundingClientRect();
var scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
var scrollLeft = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
return {x:box.left + scrollLeft, y:box.top + scrollTop}; //
}
return {x:0,y:0};
}
var eyejsTest3=function(id){
var node=eyejsGetNode3(id);
alert("Y坐标"+node.y);
}
</script>
案例下载地址: http://www.eyejs.com/html/66/n-166.html