prototype对于标签定位的一些BUG [摘]
2006-12-10 15:46
183 查看
http://www.blogjava.net/errorfun/archive/2006/12/09/86536.html
问题起因:
在原来产品中实现的 ajax tree上面添加拖拽效果,为了方便,使用了prototype来简化开发。代码中使用了Poistion.absolutize来改变拖动标签时改变它的坐标为绝对坐标显示,拖动结束后再使用Poistion.relativize变回相对坐标。
解决过程:
其实一开始测试时都挺好的,但后来在tree上面使用时就发生问题了,在拖动过程,标签跟着鼠标的移动而改变,没有问题,但在鼠标释放后,标签并没有放置在鼠标释放的位置,而是向左和向上偏移了,而这偏移的距离刚好就是tree显示位置的left和top。在对拖动结束后的位置计算的代码,拖动过程坐标计算的代码debug了一天没有收获后,突然想到把样式中的滚动条设置(overflow-x : "auto", overflow-y: "scroll",)删掉试下,没想到就可以了。
经过反复验证,终于证实是滚动条惹的祸,接着就跟踪了prototype中的相关代码,在实现Position.absolutize方法时是这样写的:
Position.absolutize = function (element)
{
element = $(element);
if (element.style.position == 'absolute') return ;
Position.prepare();
var offsets = Position.positionedOffset(element);
var top = offsets[ 1 ];
var left = offsets[ 0 ];
var width = element.clientWidth;
var height = element.clientHeight;
element._originalLeft = left - parseFloat(element.style.left || 0 );
element._originalTop = top - parseFloat(element.style.top || 0 );
element._originalWidth = element.style.width;
element._originalHeight = element.style.height;
element.style.position = 'absolute';
element.style.top = top + 'px';
element.style.left = left + 'px';
element.style.width = width + 'px';
element.style.height = height + 'px';
} ;
其中Position.positionedOffset就是取当前标签到body的偏移量,然后将信息存入_original*的相关属性中,等到调用Position.relativize时,再从这些_original*属性中从新计算出当前标签的相对位置。
再看一下Position.relativize的实现:
嗯,处理得非常漂亮,没有存在什么问题,以下是用来测试有html,试下会有什么效果
没错,按下abs按钮后,test向下移了50px左右(第二个div的offsetTop),也向右移了一点(第二个div的offsetLeft)。(如果把overflow-y:aut去掉,则没有此情况出现)而再按下rel按钮后,test能回复正常的位置,这就表示它在算法上没有什么问题,问题出在了absolutize后的位置上了,而与位置相关的信息有 _originalTop 和_originalLeft,而它们的值是与Position.positionedOffset直接相关的,再查看了Position.positionedOffset的代码:
至此,拖动后的标签定位问题终于解决,看来有时候人应该相信自己多一点,多怀疑一下别人的代码,正所谓,读书要善疑,更何况读别人的程序。
Position.relativize = function(element)
{
element = $(element);
if (element.style.position == 'relative')
{
return;
}
Position.prepare();
element.style.position = 'relative';
var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
element.style.left = left + 'px';
element.style.top = top + 'px';
element.style.height = element._originalHeight;
element.style.width = element._originalWidth;
};
<div style="height:50px"></div>
<div style="width:500px;overflow-y:auto;height:300px">
<div style="height:200px"></div>
<div style="height:300px">
<div id="test" style="height:20px">test</div>
<input type="button" value="abs" onclick="Position.absolutize('test');">
<input type="button" value="rel" onclick="Position.relativize('test');">
</div>
</div>
Position.positionedOffset = function (element)
{
var node = element.parentElement;
var valueT = 0, valueL = 0;
do
{
valueT += element.offsetTop || 0;
valueL += element.offsetLeft || 0;
element = element.offsetParent;
if (element)
{
p = Element.getStyle(element, "position");
if (p == "relative" || p == "absolute" )
{
break;
}
}
} while (element);
return [valueL, valueT];
};
看起来似乎也无法从中找出什么毛病来。可是,查了一下html的相关文档后,发现这段代码存在着相当严重的bug。html文档里,当样式position取绝对坐标"absolute "时,其内容如下:
absolute :Object is positioned relative to parent element's position—or to the body object if its parent element is not positioned—using the top and left properties.
结合文档内容,经过测试,如果标签的所有祖先节点中,有任何一个是可滚动的(overflow,overflow-y,overflow-x其中一个属性的值为auto或scroll),那标签的绝对定位就是在此标签中的坐标位置,而不是对于BODY的。
所以positionedOffset方法没有考虑到这种情况而处理,当然在一般情况下行得通了,所以代码更改如下:
Position.positionedOffset = function (element)
{
/**//*
* 经过测试,如果标签的所有祖先节点中,有任何一个是可滚动的(overflow,overflow-y,overflow-x其中一个属性的值为auto或scroll),
* 那标签的绝对定位就是在此标签中的坐标位置,而不是对于BODY的。所以在返回时应该将此祖先节点对于body的偏移量减掉.
*/
var valueT = 0, valueL = 0;
do
{
valueT += element.offsetTop || 0;
valueL += element.offsetLeft || 0;
element = element.offsetParent;
if (element)
{
var scrollable = [element.style.overflow, element.style.overflowX, element.style.overflowY];
p = Element.getStyle(element, "position");
if (p == "relative" || p == "absolute" || scrollable.include( "auto" ) || scrollable.include( "scroll" ))
{
break;
}
}
} while (element);
return [valueL, valueT];
};
问题起因:
在原来产品中实现的 ajax tree上面添加拖拽效果,为了方便,使用了prototype来简化开发。代码中使用了Poistion.absolutize来改变拖动标签时改变它的坐标为绝对坐标显示,拖动结束后再使用Poistion.relativize变回相对坐标。
解决过程:
其实一开始测试时都挺好的,但后来在tree上面使用时就发生问题了,在拖动过程,标签跟着鼠标的移动而改变,没有问题,但在鼠标释放后,标签并没有放置在鼠标释放的位置,而是向左和向上偏移了,而这偏移的距离刚好就是tree显示位置的left和top。在对拖动结束后的位置计算的代码,拖动过程坐标计算的代码debug了一天没有收获后,突然想到把样式中的滚动条设置(overflow-x : "auto", overflow-y: "scroll",)删掉试下,没想到就可以了。
经过反复验证,终于证实是滚动条惹的祸,接着就跟踪了prototype中的相关代码,在实现Position.absolutize方法时是这样写的:
Position.absolutize = function (element)
{
element = $(element);
if (element.style.position == 'absolute') return ;
Position.prepare();
var offsets = Position.positionedOffset(element);
var top = offsets[ 1 ];
var left = offsets[ 0 ];
var width = element.clientWidth;
var height = element.clientHeight;
element._originalLeft = left - parseFloat(element.style.left || 0 );
element._originalTop = top - parseFloat(element.style.top || 0 );
element._originalWidth = element.style.width;
element._originalHeight = element.style.height;
element.style.position = 'absolute';
element.style.top = top + 'px';
element.style.left = left + 'px';
element.style.width = width + 'px';
element.style.height = height + 'px';
} ;
其中Position.positionedOffset就是取当前标签到body的偏移量,然后将信息存入_original*的相关属性中,等到调用Position.relativize时,再从这些_original*属性中从新计算出当前标签的相对位置。
再看一下Position.relativize的实现:
嗯,处理得非常漂亮,没有存在什么问题,以下是用来测试有html,试下会有什么效果
没错,按下abs按钮后,test向下移了50px左右(第二个div的offsetTop),也向右移了一点(第二个div的offsetLeft)。(如果把overflow-y:aut去掉,则没有此情况出现)而再按下rel按钮后,test能回复正常的位置,这就表示它在算法上没有什么问题,问题出在了absolutize后的位置上了,而与位置相关的信息有 _originalTop 和_originalLeft,而它们的值是与Position.positionedOffset直接相关的,再查看了Position.positionedOffset的代码:
至此,拖动后的标签定位问题终于解决,看来有时候人应该相信自己多一点,多怀疑一下别人的代码,正所谓,读书要善疑,更何况读别人的程序。
Position.relativize = function(element)
{
element = $(element);
if (element.style.position == 'relative')
{
return;
}
Position.prepare();
element.style.position = 'relative';
var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
element.style.left = left + 'px';
element.style.top = top + 'px';
element.style.height = element._originalHeight;
element.style.width = element._originalWidth;
};
<div style="height:50px"></div>
<div style="width:500px;overflow-y:auto;height:300px">
<div style="height:200px"></div>
<div style="height:300px">
<div id="test" style="height:20px">test</div>
<input type="button" value="abs" onclick="Position.absolutize('test');">
<input type="button" value="rel" onclick="Position.relativize('test');">
</div>
</div>
Position.positionedOffset = function (element)
{
var node = element.parentElement;
var valueT = 0, valueL = 0;
do
{
valueT += element.offsetTop || 0;
valueL += element.offsetLeft || 0;
element = element.offsetParent;
if (element)
{
p = Element.getStyle(element, "position");
if (p == "relative" || p == "absolute" )
{
break;
}
}
} while (element);
return [valueL, valueT];
};
看起来似乎也无法从中找出什么毛病来。可是,查了一下html的相关文档后,发现这段代码存在着相当严重的bug。html文档里,当样式position取绝对坐标"absolute "时,其内容如下:
absolute :Object is positioned relative to parent element's position—or to the body object if its parent element is not positioned—using the top and left properties.
结合文档内容,经过测试,如果标签的所有祖先节点中,有任何一个是可滚动的(overflow,overflow-y,overflow-x其中一个属性的值为auto或scroll),那标签的绝对定位就是在此标签中的坐标位置,而不是对于BODY的。
所以positionedOffset方法没有考虑到这种情况而处理,当然在一般情况下行得通了,所以代码更改如下:
Position.positionedOffset = function (element)
{
/**//*
* 经过测试,如果标签的所有祖先节点中,有任何一个是可滚动的(overflow,overflow-y,overflow-x其中一个属性的值为auto或scroll),
* 那标签的绝对定位就是在此标签中的坐标位置,而不是对于BODY的。所以在返回时应该将此祖先节点对于body的偏移量减掉.
*/
var valueT = 0, valueL = 0;
do
{
valueT += element.offsetTop || 0;
valueL += element.offsetLeft || 0;
element = element.offsetParent;
if (element)
{
var scrollable = [element.style.overflow, element.style.overflowX, element.style.overflowY];
p = Element.getStyle(element, "position");
if (p == "relative" || p == "absolute" || scrollable.include( "auto" ) || scrollable.include( "scroll" ))
{
break;
}
}
} while (element);
return [valueL, valueT];
};
相关文章推荐
- play framework 页面标签使用中 遇到的 一些小BUG
- IE下当a标签使用position:absolute绝对定位时没有点击区域的bug
- jsp中使用c:if动态加载一些属性到标签 jsp中添加锚点,页面自动定位
- MPChartAndroid轴线标签自定义的一些显示BUG
- 在IE 6中<a>标签的一些bug和解决方法
- IE中a标签绝对定位时才生的bug
- xml配置spring IOC的细节和bean标签的一些属性
- android中一些view处理(拖动,定位,显示,图层)
- Freemarker一些常用的标签及用法
- 对于文件加载完成的一些心得
- 谈下html5里面p标签的一些见解,呵呵,不是很深奥的东西
- [Web]七条对于中国大学软件专业同学一些建议 [梁振&严诺]
- 浅谈Android Fragment嵌套使用存在的一些BUG以及解决方法
- 对于宽字节注入字符的一些问题以及理解
- 对于机械键盘的一些见解(转载)
- 对于理解力的一些看法 | 我们都在实战中成长
- 转 本人对于“用例”的一些理解和总结
- 一些html5,mysql,jacascript,jquery的小标签
- 对于字符串替换或过滤一些字符
- 标签的定位position