樣式操作模塊可用于管理DOM元素的樣式、坐標和尺寸,本節講解一下坐標這一塊,
對于坐標來說,jQuery提供了一個offset方法用于獲取第一個匹配元素的坐標或者設定所有匹配元素的坐標,還有offsetParent獲取最近的定位祖先元素,position用于獲取獲取第一個匹配元素相對于最近定位祖先元素的坐標,如下:
- offset(options) ;回傳匹配元素集合中的一個元素的檔案坐標,或者設定每個元素的檔案坐標,;不能帶單位,默認是px,有兩種使用方法:
- offset() ;回傳第一個匹配元素的檔案坐標
- offset(val) ;設定每個匹配的元素的檔案坐標
- offsetParent(options) ;獲取最近的定位祖先元素
- position() ;獲取第一個匹配元素相對于最近定位祖先元素的坐標 ;如果是body元素則回傳{ top: 0, left: 0 },
也就是說如果不傳遞引數則獲取第一個匹配元素的檔案坐標,如果傳遞了引數(含有left、top的物件),則設定每個匹配元素的坐標.
舉個栗子:
writer by:大沙漠 QQ:22969969
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="http://libs.baidu.com/jquery/1.7.1/jquery.min.js"></script> <style> *{margin:0;padding:0;} div{margin:20px;width: 200px;height: 180px;position: relative;padding-top: 20px;background: #c38;} h1{margin:10px;color: #333;} </style> </head> <body> <div> <h1>123</h1> </div> <button id="b1">獲取h1元素的檔案坐標</button><br/> <button id="b2">獲取h1元素最近的定位祖先元素</button><br/> <button id="b3">獲取h1元素離最近定位祖先元素的坐標</button><br/> <button id="b4">設定h1元素的檔案坐標</button> <p></p> <script> $('#b1').click(()=>{ //獲取h1元素的檔案坐標 console.log( $('h1').offset() ) }) $('#b2').click(()=>{ //獲取h1元素最近的定位祖先元素,也就是div元素 console.log( $('h1').offsetParent() ) }) $('#b3').click(()=>{ //獲取h1元素離最近定位祖先元素的坐標,也就是相對div元素的坐標 console.log( $('h1').position() ) }) $('#b4').click(()=>{ //設定h1元素的檔案坐標,相對于整個檔案的 $('h1').offset({top:'10',left:'10'}) }) </script> </body> </html>
我們添加了一個div和一個h1,另外,div設定了relation屬性,div內的h1相對于div設定了margin屬性,另外定義了四個按鈕,分別用于獲取h1的檔案坐標、獲取h1最近的定位組件元素、獲取h1元素離最近定位祖先元素的坐標和修改h1元素的坐標,效果如下:

點擊按鈕1獲取的檔案坐標是相對于整個檔案的,按鈕2獲取的定位元素也就是div元素,按鈕3獲取的是相對于div的偏移坐標,按鈕4設定h1的檔案坐標,此時h1元素上會新增一個position:relative;屬性,jQuery經過計算在h1上設定對應的偏移地址,如下:

原始碼分析
offset的實作是通過getBoundingClientRect整個原生API來實作的,如下:
if ( "getBoundingClientRect" in document.documentElement ) { //原生方法getBoundingClientRect()回傳元素的視窗坐標,回傳值含有4個整型屬性:top、left、right、bottom jQuery.fn.offset = function( options ) { var elem = this[0], box; //elem指向第一個匹配元素 if ( options ) { //如果傳入了options引數 return this.each(function( i ) { //則遍歷匹配元素集合 jQuery.offset.setOffset( this, options, i ); //并在每個元素上呼叫jQuery.offset.setOffset(elem,options,i)設定檔案坐標, }); } if ( !elem || !elem.ownerDocument ) { //如果沒有匹配元素或匹配元素不在檔案中, return null; //則不做任何處理,立即回傳null } if ( elem === elem.ownerDocument.body ) { //如果elem是body元素 return jQuery.offset.bodyOffset( elem ); //則呼叫jQuery.offset.bodyOffset(body)回傳body元素的檔案坐標 } try { box = elem.getBoundingClientRect(); //呼叫原生方法getBoundingClientRect()回傳元素的視窗坐標,用try-catch陳述句來'吞掉'IE可能拋出的例外, } catch(e) {} var doc = elem.ownerDocument, //指向document物件 docElem = doc.documentElement; //指向html元素 // Make sure we're not dealing with a disconnected DOM node if ( !box || !jQuery.contains( docElem, elem ) ) { return box ? { top: box.top, left: box.left } : { top: 0, left: 0 }; } var body = doc.body, win = getWindow(doc), //呼叫getwindow(doc)獲取window物件 clientTop = docElem.clientTop || body.clientTop || 0, //clientTop是html或body元素的上邊框厚度 clientLeft = docElem.clientLeft || body.clientLeft || 0, //clientLeft是html或body元素的左邊框厚度 scrollTop = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop, //滾動條的垂直偏移 scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft, //滾動條的水平偏移 top = box.top + scrollTop - clientTop, //第一個元素的檔案上坐標 left = box.left + scrollLeft - clientLeft; //第一個元素的檔案左坐標 return { top: top, left: left }; //回傳第一個元素的檔案坐標 }; } else { //不支持原生方法getBoundingClientRect()時,現在大多數瀏覽器已經支持了,所以這里不討論, }
上面是獲取檔案坐標的,對于設定檔案坐標是通過jQuery.offset.setOffset()來實作的,也就是上面標紅的地方,jQuery.offset.setOffset的實作如下:
jQuery.offset = { setOffset: function( elem, options, i ) { //設定單個元素的檔案坐標, var position = jQuery.css( elem, "position" ); // set position first, in-case top/left are set even on static elem if ( position === "static" ) { //如果該元素的position屬性等于static的 elem.style.position = "relative"; //則修正為relative,使得設定的樣式left、top能夠生效, } var curElem = jQuery( elem ), //當前元素的jQuery物件 curOffset = curElem.offset(), //當前元素的檔案坐標 curCSSTop = jQuery.css( elem, "top" ), //獲取 當前元素的計算樣式top,帶有單位 curCSSLeft = jQuery.css( elem, "left" ), //獲取 當前元素的計算樣式left,帶有單位 calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1, //如果當前屬性樣式position是absolute或fixed,并且樣式left或top是auto,則設定calculatePosition為true, props = {}, curPosition = {}, curTop, curLeft; // need to be able to calculate position if eit her top or left is auto and position is either absolute or fixed if ( calculatePosition ) { //如果calculatePosition為true,修正curTop和curLeft坐標, curPosition = curElem.position(); //通過.position()獲取當前元素相對于最近定位祖先元素或body元素的坐標 curTop = curPosition.top; //獲取組件元素的top curLeft = curPosition.left; //獲取組件的left } else { //將curCSSTop、curCSSLeft決議為數值,以便參與計算, curTop = parseFloat( curCSSTop ) || 0; curLeft = parseFloat( curCSSLeft ) || 0; } if ( jQuery.isFunction( options ) ) { //如果options是函式 options = options.call( elem, i, curOffset ); //則執行該函式,取其回傳值作為要設定的檔案坐標, } if ( options.top != null ) { //計算最終的行內樣式top props.top = ( options.top - curOffset.top ) + curTop; } if ( options.left != null ) { //計算最終的行內樣式left props.left = ( options.left - curOffset.left ) + curLeft; } if ( "using" in options ) { //如果引數options中有回呼函式using,則呼叫 options.using.call( elem, props ); } else { curElem.css( props ); //否則呼叫.css(name,value)方法設定最終的行內樣式top、left, } } };
從原始碼里可以看到,如果元素有設定了absolute則會獲取祖先元素的的偏移,然后經過一些運算獲取最后的值,最后通過css()修改樣式來實作最后的定位,
對于offsetParent來說,它的實作如下:
jQuery.fn.extend({ offsetParent: function() { //獲取最近的定位祖先元素,就是CSS position屬性被設定為relative、absolute 或 fixed 的元素,回傳一個jQuery物件,包含所有祖先元素, return this.map(function() { var offsetParent = this.offsetParent || document.body; //offsetParent是最近的定位祖先元素;如果沒有找到,則回傳body元素, while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) { //如果找到的祖先元素的樣式position是static,則繼續沿著樹向上找,直到遇到body元素或html元素為止, offsetParent = offsetParent.offsetParent; } return offsetParent; //回傳的定位組選元素將被添加到新構造的jQuery物件上, }); } })
offsetParent是原生的DOM操作的API,用于獲取第一個祖定位元素,所有瀏覽器都支持的,這里就是把它進行了一個封裝而已,
position()比較簡單,通過offsetParent()獲取第一個祖先節點的檔案坐標,然后用組件節點的top減去當前節點的top,組件節點的left減去當前節點的left,回傳一個相對位置,僅此而已,代碼就不貼了,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/28077.html
標籤:jQuery
上一篇:jquery 屬性名修改
下一篇:JS獲得天數差異
