1. 程式人生 > >獲取元素相對於文件的偏移量以及元素相對於父元素的偏移量

獲取元素相對於文件的偏移量以及元素相對於父元素的偏移量

問題1:如果獲取元素距離文件頂部的距離?

      var rect=$('#elem')[0].getBoundingClientRect();
	//獲取元素距離文件頂部的距離
	var top=rect.top+(window.pageYOffset||document.documentElement.scrollTop)-(document.documentElement.clientTop||0);
	var left=rect.left+(window.pageXOffset||document.documentElement.scrollLeft)-(document.documentElement.clientLeft||0);
該方法的思路來自己jQuery的offset方法
問題2:如何獲取元素相對於被定位的祖先元素的距離?

也就是相對於被定位的祖輩元素的座標。該函式只對可見元素有效。所謂"被定位的元素",就是元素的CSS position屬性值為absolute、relative或fixed(只要不是預設的static即可)。
如果元素的position是fixed,這時候是相對於瀏覽器的可視區域來定位的

  var  offset = $("#elem")[0].getBoundingClientRect();
 //var marginTop=window.getComputedStyle($("#elem")[0],null)['margin-top'];
   var marginTop=jQuery.css( $("#elem")[0], "marginTop", true );
   //這種方式獲取到的將會是數字,而不是含有px的字串!
   console.log(offset.top-marginTop);

這裡也可以用window.getComputedStyle來獲取margin-top等屬性,只是jQuery.css對通過getComputedStyle獲取到的值進行了處理了,轉化成為具體的畫素值了!對於position為fixed的元素獲取其距離文件頂部的距離其實就是相對於瀏覽器的視口來說的,但是很顯然jQuery獲取到被定位的祖先元素的距離是從子元素的margin開始計算的,可以閱讀部落格javascript中那些計算元素位置的方法和jQuery位置計算方法比較

如果position不是fixed,以下面的HTML為例
<div id="elem" style="position:absolute;border:1px solid yellow;width:50px;height:50px;">
	  <div id="n2" style="background-color:red;width:20px;height:20px;">	
	</div>
</div>
JS部分
      var elem=$("#n2")[0];
	  var jelem=$(elem);
     var offsetParent=jelem.offsetParent();
	 //獲取該元素最近的被定位的父元素的座標!
	 var parentOffset = offsetParent.offset();  
	 //獲取該最近的父元素相對於文件的距離
	 var offset=jelem.offset();
	 //獲取自己到文件的距離
	 var top=offset.top-parentOffset.top-jQuery.css( offsetParent[ 0 ], "borderTopWidth", true )-jQuery.css( elem, "marginTop", true );
	 //自己到文件的距離-父元素到文件的距離-父元素的borderTop-子元素的marginTop!
	 console.log(top);
如果獲取子元素到父元素的left,那麼可以通過下面的公式
      var elem=$("#n2")[0];
	  var jelem=$(elem);
     var offsetParent=jelem.offsetParent();
	 //獲取該元素最近的被定位的父元素的座標!
	 var parentOffset = offsetParent.offset();  
	 //獲取該最近的父元素相對於文件的距離
	 var offset=jelem.offset();
	 //獲取自己到文件的距離
	 var left=offset.left-parentOffset.left-jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true )-jQuery.css( elem, "marginLeft", true );
	 //自己到文件的距離-父元素到文件的距離-父元素的borderLeft-子元素的marginLeft!
	 console.log(offset.left);
	 //列印20
	 console.log(parentOffset.left);
	 //9
	 console.log(jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true ));
	 //列印1
	 console.log(jQuery.css( elem, "marginLeft", true ));
	 //列印10
獲取元素到父元素的的距離的方法=當前元素到文件的距離(getBoundingClientRect到內容結束,也就是到border結束!)-父元素到文件的距離(getBoundClientRect)-元素的borderWidth-子元素的marginTop屬性!

問題3:offsetParent是什麼,如果父元素的樹中沒有被定位的元素,那麼jQuery的offsetParent方法會獲取到html元素,而不是body元素?

解答:沒錯,jQuery預設的offsetParent是html元素,而js預設的offsetParent卻是body元素,不過js在計算偏移量的時候還是按照html來計算的!參見 無定位父元素時offsetParent為body,但是offsetTop/offsetLeft計算距離從html開始

<div id="elem" style="position:absolute;border:1px solid yellow;width:50px;height:50px;">
	    <div id="n2" style="background-color:red;width:20px;height:20px;margin-left:10px;">
		</div>
	</div>
js部分是
window.onload=function()
{
     var result=$("div").offsetParent();
	 //列印[html, div#elem, prevObject: jQuery.fn.init[2], context: document]
	 //獲取所有呼叫元素的offsetParent集合
	 console.log(result);
}
第一個div元素的offsetParent是html元素,第二個div元素是父元素div,map就是得到所有呼叫元素的offsetParent集合
offsetParent: function() {
		//遍歷呼叫物件的DOM,執行特定的函式,得到所有呼叫物件的offsetParent集合
		return this.map(function() {
			//只要在html之前有非static的元素,這時候獲取到就是offsetParent也就是最近的被定位的父元素
			var offsetParent = this.offsetParent || docElem;
			while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position" ) === "static" ) ) {
				offsetParent = offsetParent.offsetParent;
			}
			return offsetParent || docElem;
		});
	}
從這裡看出,呼叫offsetParent獲取到的是所有呼叫元素的offsetParent組成的集合。如果所有元素的position都是static,那麼獲取到的就是html元素,也就是預設是html元素!