efa's blog

以用户角度出发,你就已经成功一半了.

导航

<2005年6月>
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789

统计

常用链接

留言簿(18)

我参与的团队

随笔分类

随笔档案

文章分类

文章档案

Bi report

dba

info security

other

perl

php

python

tech blogs

tech websites

最新随笔

搜索

积分与排名

最新评论

阅读排行榜

评论排行榜

[WEB BASE] 获得DIV容器中控件的真实位置

           今天在修正一些需求,在使用以往封装好日期htc,发现了一个bug,如下,在正常情况下点击输入框可将隐藏的htc控件能显示在input正下方。
           但在滚动层的时候再点击输入框就出现了问题了。
           由于blogjava不支持htc上传。所以没演示 : (

有BUG的日历HTC
日期:

          测试可发现日历控件偏位了。滚动条向下划,它也不断向下偏离input。

查看htc源码。发现其是用getDim(el)函数取得input的X,Y 坐标然后将日历控制定位的。
 
有bug的取得控件位置的javascript代码
function getDim(el){
 for (var lx=0,ly=0;el!=null;
lx+=el.offsetLeft,ly+=el.offsetTop,el=el.offsetParent); // 用offsetLeft , offsetTop 循环累加
 return {x:lx,y:ly}  //返回 input模式x,y 坐标
}


现在将input 框架放到div 容器中,然而也设置了CSS(position:relative;overflow:auto; )
 overflow:auto是指当 内容超出块的情况下,自动显示滚动条
如图分析:
box.gif
图1是正常没有滚动的情况,
图2、3是滚动后的效果(这两种情况就会出现问题)

原有bug代码
 for (var lx=0,ly=0;el!=null;
lx+=el.offsetLeft,ly+=el.offsetTop,el=el.offsetParent);
用offsetParent 中的offsetLeft  ,offsetTop 不断累加, 在通常情况下是没有问题的。
但放到容器中,并且有滚动条的情况就会出现问题了。

先来回顾一下dhtml中对象中的几个属性(更多请看DHTL参考书)

offsetParent 
------------------------
Retrieves a reference to the container object that defines the offsetTop and offsetLeft properties of the object.

offsetHeight 
------------------------
Retrieves the height of the object relative to the layout or coordinate parent, 
as specified by the offsetParent property.  

offsetLeft 
------------------------
Retrieves the calculated left position of the object relative to the layout or coordinate parent, 
as specified by the offsetParent property.  

offsetParent 
------------------------
Retrieves a reference to the container object that defines the offsetTop and offsetLeft properties of the object. 

offsetTop  
------------------------
Retrieves the calculated top position of the object relative to the layout or coordinate parent, as specified by the offsetParent property.  

offsetWidth 
------------------------
Retrieves the width of the object relative to the layout or coordinate parent, 
as specified by the offsetParent property.  


clientHeight 
------------------------
Retrieves the height of the object including padding, but not including margin, border, or scroll bar.  

clientLeft 
------------------------
Retrieves the distance between the offsetLeft property and the true left side of the client area. 
 
clientTop 
------------------------
Retrieves the distance between the offsetTop property and the true top of the client area.  

clientWidth 
------------------------
Retrieves the width of the object including padding, but not including margin, border, or scroll bar. 


scrollHeight 
------------------------
Retrieves the scrolling height of the object.  

scrollLeft 
------------------------
Sets or retrieves the distance between the left edge of the object and the leftmost portion of the content currently visible in the window.  

scrollTop 
------------------------
Sets or retrieves the distance between the top of the object and the topmost portion of the content currently visible in the window.  

scrollWidth 
------------------------
Retrieves the scrolling width of the object. 

显然,原有bug的代码使用 el.offsetTop  (取得了当前object相对于其父object的距离),
当div滚动时。
这样计算其真实高度就会有问题(大于其实际的高度)


代码改进,当发现父的tag name 为DIV容器,并设置了相关的style   CSS(position:relative;overflow:auto; )
那么我们就不再累加这个 offsetTop,取而代之的公式应该是再减去滚动上去的隐藏了的高度,也就是的值,如上图可清晰发现:

 ly = ly + (el.offsetTop - el.scrollTop);


修正后取得控件位置的javascript代码,另外左右滚动的相应原理,在这里没写出来

function getDim(el){
 for (var lx=0,ly=0;el!=null;
  lx+=el.offsetLeft,ly+=el.offsetTop,el=el.offsetParent)
  {
      if(el.tagName.toLowerCase()=="div" && el.style.position=="relative")
      {
          ly = ly - el.offsetTop;  
          ly = ly + (el.offsetTop - el.scrollTop);
      }
  };
 return {x:lx,y:ly}
}


BUG 修正后日历HTC
日期:


补充:
Box model

posted on 2005-06-29 21:01 一凡@ITO 阅读(2223) 评论(4)  编辑  收藏

评论

# re: [WEB BASE] 获得DIV容器中控件的真实位置 2005-06-30 09:48 emu

只考虑了父容器是div的情况,有没有考虑过有写时候我们会有div嵌套之类的情况呢?
以前看很多人计算的时候都是一层层的递归拿上一层的位置累加来确定当前元素在页面中的真实位置。
另一种可能的做法是,让要插入的元素和原来的元素放在同一个容器中,再确定他们的相对位置。  回复  更多评论   

# re: [WEB BASE] 获得DIV容器中控件的真实位置 2005-06-30 10:53 一天一点

div嵌套之类的情况是没有问题。
我这里用的是for循环所有父

for (var lx=0,ly=0;el!=null;
lx+=el.offsetLeft,ly+=el.offsetTop,el=el.offsetParent)


每出现,再处理
if(el.tagName.toLowerCase()=="div" && el.style.position=="relative")
{
ly = ly - el.offsetTop;
ly = ly + (el.offsetTop - el.scrollTop);
}   回复  更多评论   

# re: [WEB BASE] 获得DIV容器中控件的真实位置 2005-06-30 15:16 emu

呵呵原来递归在这里啊:
el=el.offsetParent
早上没仔细看。  回复  更多评论   

# re: [WEB BASE] 获得DIV容器中控件的真实位置 2007-08-10 14:26 陈高昌

你的这个问题没有完全解决,当你手动去移动滚动条的时候,scrollTop会受影响,导致算出来的结果不一样  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航: