问题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方法
也就是相对于被定位的祖辈元素的坐标。该函数只对可见元素有效。所谓"被定位的元素",就是元素的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元素!