我目前正在研究jquery并注意到jquery中的大多数方法都有一个设置和getter版本。即该方法用作setter或getter,具体取决于传递给方法的参数的类型/数量。
一个例子是http://yourserver:port/_cat/thread_pool。
但是我也注意到jquery offset() method只有一个getter版本,并且它的setter版本丢失了。
有没有人知道为什么position()
方法没有setter版本?我不完全确定,但我认为在某些情况下,setter版本会很有用。
答案 0 :(得分:5)
这是因为offset()
和position()
在目的和内在上都大不相同。作者试图在the docs中进行解释:
.position()
方法使我们能够检索的当前位置 元素(特别是其边距框)相对于偏移父级 (特别是其填充框,其中不包括边距和边框)。 将其与.offset()
进行对比,后者可检索当前位置 相对于文档。
但是,最好的解释是像往常一样在源中。 offset()
getter非常简单:检查元素在实时DOM中的存在之后,将其框与文档的框进行比较,然后滚动调整:
// If we don't have gBCR, just use 0,0 rather than error
// BlackBerry 5, iOS 3 (original iPhone)
if ( typeof elem.getBoundingClientRect !== "undefined" ) {
box = elem.getBoundingClientRect();
}
win = getWindow( doc );
return {
top: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0),
left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
};
(在2.x分支中更直接,顺便说一句;无需gBCR检查)
现在,position()
getter仅在目标元素已应用position: fixed
时相对简单-只需获取gBCR结果作为偏移量即可。
否则,事情会变得混乱。首先,算法应定位“真实” offsetParent-位置最接近的前任而不是静态。如果未找到,则使用documentElement
:
// key part of `offsetParent()` method
while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) &&
jQuery.css( offsetParent, "position" ) === "static" ) ) {
offsetParent = offsetParent.offsetParent;
}
return offsetParent || documentElement;
然后代码计算offsetParent
偏移量-如果使用documentElement
或top: 0, left: 0
则使用其坐标。而且不要忘记边界!
var parentOffset = { top: 0, left: 0 },
// ... later on
if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
parentOffset = offsetParent.offset();
}
// Add offsetParent borders
parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
最后,比较偏移量-现在还考虑了元素的边距:
// Subtract parent offsets and element margins
// note: when an element has margin: auto the offsetLeft and marginLeft
// are the same in Safari causing offset.left to incorrectly be 0
return {
top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
};
难题的第三部分,offset()
setter。以下是关键部分:
// set position first, in-case top/left are set even on static elem
if ( position === "static" ) {
elem.style.position = "relative";
}
curOffset = curElem.offset();
curCSSTop = jQuery.css( elem, "top" );
curCSSLeft = jQuery.css( elem, "left" );
calculatePosition = ( position === "absolute" || position === "fixed" ) &&
jQuery.inArray( "auto", [ curCSSTop, curCSSLeft ] ) > -1;
// need to be able to calculate position if either top or left
// is auto and position is either absolute or fixed
if ( calculatePosition ) {
curPosition = curElem.position();
curTop = curPosition.top;
curLeft = curPosition.left;
} else {
curTop = parseFloat( curCSSTop ) || 0;
curLeft = parseFloat( curCSSLeft ) || 0;
}
// ...
if ( options.top != null ) {
props.top = ( options.top - curOffset.top ) + curTop;
}
if ( options.left != null ) {
props.left = ( options.left - curOffset.left ) + curLeft;
}
// ...
curElem.css( props );
从本质上讲,这又非常简单:计算元素的偏移量,并通过差异来修改其top
和left
。复杂的部分涵盖position: fixed
与auto
或top
的{{1}}值组合的情况。
在思考left
设置器的外观时,会出现两个问题。
首先,静态元素应该怎么做?如上所示,position
设置器仅将其offset
重写为position
;我们在这里应该采取相同的方式-处理relative
的突然变化吗?
第二,每次调用setter时,都应重新计算offsetParent
的填充框。当然,它在很大程度上取决于用例,但是-我们不应该仅在元素挂载并重做布局更改事件时才进行此计算吗?如果我们应该,offsetParent
的二传手与现有的offset()
一起已经满足了我们的所有需求?
这些问题可能解释了为什么该选项尚未在jQuery中实现-尽管jQuery UI中已经存在该选项。该插件不依赖于其他jQuery UI组件,但是its latest version长约500行。
如果您确实认为它也应该是jQuery的一部分,则只需在jQuery跟踪器上提出一个相应的问题即可;至少我还没有找到anything related。