1、offset()javascript
做用:
返回被選元素相對於文檔(document)的偏移座標css
2、三種狀況使用:java
一、$()
.offset()node
<body>
<script src="jQuery.js"></script>
<p id="pTwo">這是divTwo</p>
<script>
$("#pTwo").offset() //{top: 16, left: 8}
</script>
</body>
複製代碼
源碼:瀏覽器
//返回目標元素相對於doucument的偏移座標,
//即距離瀏覽器左上角的距離
// 返回偏移座標:$(selector).offset()
// 設置偏移座標:$(selector).offset({top:value,left:value})
// 使用函數設置偏移座標:$(selector).offset(function(index,currentoffset))
// offset() relates an element's border box to the document origin
//源碼10500行
//options即參數
//arguments是參數對象
offset: function( options ) {
// Preserve chaining for setter
//若是是有參數的,參數是undefined則返回目標元素自己,
//不然爲每一個目標元素設置options
console.log(options,arguments,'arguments10476')
//$().offset()不走這裏
if ( arguments.length ) {
console.log('aaa','vvv10507')
return options === undefined ?
this :
this.each( function( i ) {
//爲每一個目標元素設置options
jQuery.offset.setOffset( this, options, i );
} );
}
var rect, win,
//獲取DOM節點
elem = this[ 0 ];
if ( !elem ) {
return;
}
// jQuery不支持獲取隱藏元素的偏移座標。
// 同理,也沒法取得隱藏元素的 border, margin, 或 padding 信息
//因此若是元素是隱藏的,默認返回0值
// Return zeros for disconnected and hidden (display: none) elements (gh-2310)
// Support: IE <=11 only
// Running getBoundingClientRect on a
// disconnected node in IE throws an error
//對IE的特殊處理
if ( !elem.getClientRects().length ) {
return { top: 0, left: 0 };
}
// Get document-relative position by adding viewport scroll to viewport-relative gBCR
//返回元素的大小及其相對於視口的位置
//https://developer.mozilla.org/zh-CN/docs/Web/API/Element/getBoundingClientRect
rect = elem.getBoundingClientRect();
//返回所屬文檔的默認窗口對象(只讀)
//原點座標
win = elem.ownerDocument.defaultView;
//pageXOffset,pageYOffset 至關於 scrollX 和 scrollY
//返回文檔在窗口左上角水平 x 和垂直 y 方向滾動的像素
return {
//16 0
//
top: rect.top + win.pageYOffset,
//8 0
left: rect.left + win.pageXOffset
};
},
複製代碼
解析:
因爲$()
.offset()沒有參數,因此源碼裏的兩個 if
能夠忽略,因此offset()
的本質即:app
let p = document.getElementById("pTwo");
let rect=p.getBoundingClientRect()
//返回所屬文檔的默認窗口對象(只讀)
//原點座標
let win = p.ownerDocument.defaultView;
let offsetObj={
top: rect.top + win.pageYOffset,
left: rect.left + win.pageXOffset
}
console.log(offsetObj,'win18')
複製代碼
(1)getBoundingClientRect()
該方法用於獲取某個元素相對於視窗的位置集合,並返回一個對象,該對象中有top, right, bottom, left等屬性,簡單點就是相對於原座標(默認是左上角)的偏移量函數
(2)window.pageXOffset、window.pageYOffset
返回文檔在窗口左上角水平 x 和垂直 y 方向滾動的像素,至關於 scrollX 和 scrollY,簡單點就是滾動的偏移量ui
因此offset()
的本質即:
相對於原座標的偏移量+滾動的偏移量的總和。this
二、$()
.offset({top:15,left:15})spa
$("#pTwo").offset({top:15,left:15})
複製代碼
源碼:
當有參數的時候,就會走 if
中,經過jQuery.offset.setOffset( )
來處理:
if ( arguments.length ) {
return options === undefined ?
this :
this.each( function( i ) {
//爲每一個目標元素設置options
jQuery.offset.setOffset( this, options, i );
} );
}
複製代碼
//offset()的關鍵方法
//源碼10403行
jQuery.offset = {
setOffset: function( elem, options, i ) {
var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
//獲取元素的position屬性的值
//static
position = jQuery.css( elem, "position" ),
//過濾成標準jQuery對象
curElem = jQuery( elem ),
props = {};
// Set position first, in-case top/left are set even on static elem
//指定相對定位relative
if ( position === "static" ) {
elem.style.position = "relative";
}
//{left:8,top:16}
curOffset = curElem.offset();
//0px
curCSSTop = jQuery.css( elem, "top" );
//0px
curCSSLeft = jQuery.css( elem, "left" );
// 若是定位position是(絕對定位absolute或固定定位fixed),
// 而且top,left屬性包含auto的話
//false
calculatePosition = ( position === "absolute" || position === "fixed" ) &&
( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -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 {
//0 0
curTop = parseFloat( curCSSTop ) || 0;
curLeft = parseFloat( curCSSLeft ) || 0;
}
//若是傳的參數是function{}的話
if ( isFunction( options ) ) {
// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
options = options.call( elem, i, jQuery.extend( {}, curOffset ) );
}
//若是傳的參數的有top值
if ( options.top != null ) {
//參數 top - offset().top + element.top
props.top = ( options.top - curOffset.top ) + curTop;
}
//若是傳的參數的有left值
if ( options.left != null ) {
//參數 left - offset().left + element.left
props.left = ( options.left - curOffset.left ) + curLeft;
}
//本身沒見過使用 using 的狀況。。
if ( "using" in options ) {
options.using.call( elem, props );
}
//因此通常走這裏,爲當前元素設置top,left屬性
else {
//position:relative
//top:xxx
//left:xxx
curElem.css( props );
}
}
};
複製代碼
解析:
(1)先判斷當前元素的 position 的值,沒有設置 position 屬性的話,默認爲 relative,並獲取元素的 top、left 屬性的值
(2)返回一個對象 obj,obj 的 top 是參數的 top - 默認偏移(offset)的 top + position 設置的 top(沒有設置,默認爲0)
,obj 的 left 同理。
也就是說 offset({top:15,;eft:15}) 的本質爲:
參數的屬性減去對應的默認offset屬性加上position上的對應屬性。
//僞代碼
offset().top = elem. getBoundingClientRect().top + document. pageYOffset
top: offset({top:15}).top - offset().top + position.top
也就是:
offset({top:15}).top - (elem. getBoundingClientRect().top + document. pageYOffset) + position.top
複製代碼
三、$()
.offset(function(){})
$("#pTwo").offset(function(index,currentoffset){
let newPos={};
newPos.left=currentoffset.left+15;
newPos.top=currentoffset.top+15;
return newPos;
});
複製代碼
源碼:
//若是傳的參數是function{}的話
if ( isFunction( options ) ) {
// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
options = options.call( elem, i, jQuery.extend( {}, curOffset ) );
}
複製代碼
解析:
讓當前元素經過call 去調用參數中的 function(){} 方法,call 的參數必須一個一個放進去,上面源碼中,call 參數有 i、jQuery.extend( {}, curOffset )
jQuery.extend()
,但這裏的做用 不用看源碼,也知道是將 element.offset() 的屬性賦值給新建的空對象 {} 。因此 $().offset(function(){}) 的本質即:相對於 element.offset() ,對其 top,left進行操做,而不是像 offset({top:xxx,left:xxx}) 那樣相對於左上角原點進行操做(這樣就須要先減去offset()中的top、left的值了)。
本文結束,五一愉快~
(完)