jQuery源码解析之position()
position()
作用:
返回被選元素相對于父元素(parent)的偏移坐標
使用:
直接調用$().position()即可,該方法沒有 arguments(參數對象)
<script?src="jQuery.js"></script>
<p?id="pTwo">這是divTwo</p>
<script>
??$("#pTwo").position()?//{top:?0,?left:?8}
</script>
</body>
復制代碼
源碼:
??//?返回被選元素相對于父元素(parent)的偏移坐標????//?可以理解成被選元素設置為absolute,
????//?然后設置left、top的值就是相對于父元素的偏移坐標
????//?源碼10571行
????//?position()?relates?an?element's?margin?box?to?its?offset?parent's?padding?box
????//?This?corresponds?to?the?behavior?of?CSS?absolute?positioning
????position:?function()?{
??????//?如果DOM元素不存在,直接返回
??????if?(?!this[?0?]?)?{
????????return;
??????}
??????var?offsetParent,?offset,?doc,
????????elem?=?this[?0?],
????????parentOffset?=?{?top:?0,?left:?0?};
??????//?position:fixed?elements?are?offset?from?the?viewport,?which?itself?always?has?zero?offset
??????//?position:fixed的元素,是相對于瀏覽器窗口進行定位的,
??????//?所以它的偏移就是getBoundingClientRect(),即獲取某個元素相對于視窗的位置
??????if?(?jQuery.css(?elem,?"position"?)?===?"fixed"?)?{
????????//?Assume?position:fixed?implies?availability?of?getBoundingClientRect
????????offset?=?elem.getBoundingClientRect();
??????}
??????//?除去position是fixed的情況
??????else?{
????????//?獲取被選元素相對于文檔(document)的偏移坐標
????????offset?=?this.offset();
????????//?Account?for?the?*real*?offset?parent,?which?can?be?the?document?or?its?root?element
????????//?when?a?statically?positioned?element?is?identified
????????doc?=?elem.ownerDocument;
????????//定位目標元素的父元素(position不為static的元素)
????????offsetParent?=?elem.offsetParent?||?doc.documentElement;
????????//?如果父元素是<body>/<html>的話,將父元素重新定位為它們的父元素
????????//?body的父元素是html,html的父元素是document
????????while?(?offsetParent?&&
????????(?offsetParent?===?doc.body?||?offsetParent?===?doc.documentElement?)?&&
????????jQuery.css(?offsetParent,?"position"?)?===?"static"?)?{
??????????offsetParent?=?offsetParent.parentNode;
????????}
????????//?如果定位父元素存在,并且不等于目標元素,并且定位元素類型是?"元素類型"
????????if?(?offsetParent?&&?offsetParent?!==?elem?&&?offsetParent.nodeType?===?1?)?{
??????????//?Incorporate?borders?into?its?offset,?since?they?are?outside?its?content?origin
??????????parentOffset?=?jQuery(?offsetParent?).offset();
??????????//?這兩行代碼的意思是父元素的offset()要從padding算起,不包括border
??????????//?所以需要去掉border
??????????//?jQuery.css(?element,?"borderTopWidth",?true?)的?true?表示返回數字,而不帶單位?px
??????????parentOffset.top?+=?jQuery.css(?offsetParent,?"borderTopWidth",?true?);
??????????parentOffset.left?+=?jQuery.css(?offsetParent,?"borderLeftWidth",?true?);
????????}
??????}
??????//?Subtract?parent?offsets?and?element?margins
??????//?可以看出,$().position()的本質是目標元素的offset()減去父元素的offset(),同時還要算上目標元素的margin,因為盒子模型(關鍵)。
??????//(注意:offset()的本質是getBoundingClientRect()的top、left?+?pageYOffset、pageXOffset)
??????return?{
????????top:?offset.top?-?parentOffset.top?-?jQuery.css(?elem,?"marginTop",?true?),
????????left:?offset.left?-?parentOffset.left?-?jQuery.css(?elem,?"marginLeft",?true?)
??????};
????},
復制代碼
解析:
整體上看,是一個 if(...fixed) { } esle { } 語句
(1)if ( jQuery.css( elem, "position" ) === "fixed" )
????????//?Assume?position:fixed?implies?availability?of?getBoundingClientRect
????????offset?=?elem.getBoundingClientRect();
}
return?{
????????top:?offset.top?-?parentOffset.top?-?jQuery.css(?elem,?"marginTop",?true?),
????????left:?offset.left?-?parentOffset.left?-?jQuery.css(?elem,?"marginLeft",?true?)
??????};
復制代碼
由于position:fixed的元素,是相對于瀏覽器窗口進行定位的,所以它的偏移就是getBoundingClientRect(),即獲取某個元素相對于視窗的位置。
注意:
① getBoundingClientRect() 計算的是目標元素的border的位置(左上角),是不包括margin的
② 如果不加上margin的話(代碼是通過減去,來算上margin的),是不準確的,看下圖
所以源碼最后會:
-?jQuery.css(?elem,?"marginTop",?true?)-?jQuery.css(?elem,?"marginLeft",?true?)
復制代碼
(2)jQuery.css( elem, "width", true )
true的作用是返回該屬性的數字,而不帶單位 px
(3)定位父元素存在,并且不等于目標元素,并且定位元素類型是 "元素類型"的話
if?(?offsetParent?&&?offsetParent?!==?elem?&&?offsetParent.nodeType?===?1?)復制代碼
是要減去border屬性的值的
parentOffset.top?+=?jQuery.css(?offsetParent,?"borderTopWidth",?true?);parentOffset.left?+=?jQuery.css(?offsetParent,?"borderLeftWidth",?true?);
復制代碼
為啥?舉個例子:
let?p=document.querySelector("#pTwo")console.log(p.getBoundingClientRect(),'pTwo11');?//x:8,y:16
復制代碼
設置 borderLeftWidth 為 8 像素
let?p=document.querySelector("#pTwo")p.style.borderLeftWidth='8px'
console.log(p.getBoundingClientRect(),'pTwo11');?//x:8,y:16
復制代碼
可以看到getBoundingClientRect()指定坐標是到border上的,這是不準確的,因為在里面的子元素的位置也會受父元素的border影響,所以父元素的坐標需要越過border
綜上:
可以看出,$().position()的本質是目標元素的 offset() 減去父元素的 offset(),同時還要算上目標元素的 margin,算上父元素的border。
(注意:offset()的本質是getBoundingClientRect()的top、left + pageYOffset、pageXOffset)
Github:
github.com/AttackXiaoJ…
(完)
總結
以上是生活随笔為你收集整理的jQuery源码解析之position()的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第五章 树和二叉树
- 下一篇: WinCE5.0如何安装.NET3.5