`
deng131
  • 浏览: 675281 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

jQuery中offset()和position()方法

阅读更多
通过源码来学习offset和position方法才能更深入理解其实现
jQuery的offset()方法

获取匹配元素在当前视口的相对偏移。
返回的对象包含两个整形属性:top 和 left。此方法只对可见元素有效。

jQuery的position()方法

获取匹配元素相对父元素的偏移。
返回的对象包含两个整形属性:top 和 left。此方法只对可见元素有效。

jQuery1.4源码:

var rtable = /^t(?:able|d|h)$/i,
	rroot = /^(?:body|html)$/i;

if ( "getBoundingClientRect" in document.documentElement ) {
	jQuery.fn.offset = function( options ) {
		var elem = this[0], box;

		if ( options ) { 
			return this.each(function( i ) {
				jQuery.offset.setOffset( this, options, i );
			});
		}

		if ( !elem || !elem.ownerDocument ) {
			return null;
		}

		if ( elem === elem.ownerDocument.body ) {
			return jQuery.offset.bodyOffset( elem );
		}

		try {
			box = elem.getBoundingClientRect();
		} catch(e) {}

		var doc = elem.ownerDocument,
			docElem = doc.documentElement;

		// Make sure we're not dealing with a disconnected DOM node
		if ( !box || !jQuery.contains( docElem, elem ) ) {
			return box || { top: 0, left: 0 };
		}

		var body = doc.body,
			win = getWindow(doc),
			clientTop  = docElem.clientTop  || body.clientTop  || 0,
			clientLeft = docElem.clientLeft || body.clientLeft || 0,
			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 {
	jQuery.fn.offset = function( options ) {
		var elem = this[0];

		if ( options ) { 
			return this.each(function( i ) {
				jQuery.offset.setOffset( this, options, i );
			});
		}

		if ( !elem || !elem.ownerDocument ) {
			return null;
		}

		if ( elem === elem.ownerDocument.body ) {
			return jQuery.offset.bodyOffset( elem );
		}

		jQuery.offset.initialize();

		var computedStyle,
			offsetParent = elem.offsetParent,
			prevOffsetParent = elem,
			doc = elem.ownerDocument,
			docElem = doc.documentElement,
			body = doc.body,
			defaultView = doc.defaultView,
			prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
			top = elem.offsetTop,
			left = elem.offsetLeft;

		while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
			if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
				break;
			}

			computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
			top  -= elem.scrollTop;
			left -= elem.scrollLeft;

			if ( elem === offsetParent ) {
				top  += elem.offsetTop;
				left += elem.offsetLeft;

				if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
					top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
					left += parseFloat( computedStyle.borderLeftWidth ) || 0;
				}

				prevOffsetParent = offsetParent;
				offsetParent = elem.offsetParent;
			}

			if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
				top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
				left += parseFloat( computedStyle.borderLeftWidth ) || 0;
			}

			prevComputedStyle = computedStyle;
		}

		if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
			top  += body.offsetTop;
			left += body.offsetLeft;
		}

		if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
			top  += Math.max( docElem.scrollTop, body.scrollTop );
			left += Math.max( docElem.scrollLeft, body.scrollLeft );
		}

		return { top: top, left: left };
	};
}

jQuery.offset = {
	initialize: function() {
		var body = document.body, container = document.createElement("div"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.css(body, "marginTop") ) || 0,
			html = "<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";

		jQuery.extend( container.style, { position: "absolute", top: 0, left: 0, margin: 0, border: 0, width: "1px", height: "1px", visibility: "hidden" } );

		container.innerHTML = html;
		body.insertBefore( container, body.firstChild );
		innerDiv = container.firstChild;
		checkDiv = innerDiv.firstChild;
		td = innerDiv.nextSibling.firstChild.firstChild;

		this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
		this.doesAddBorderForTableAndCells = (td.offsetTop === 5);

		checkDiv.style.position = "fixed";
		checkDiv.style.top = "20px";

		// safari subtracts parent border width here which is 5px
		this.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15);
		checkDiv.style.position = checkDiv.style.top = "";

		innerDiv.style.overflow = "hidden";
		innerDiv.style.position = "relative";

		this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);

		this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);

		body.removeChild( container );
		body = container = innerDiv = checkDiv = table = td = null;
		jQuery.offset.initialize = jQuery.noop;
	},

	bodyOffset: function( body ) {
		var top = body.offsetTop,
			left = body.offsetLeft;

		jQuery.offset.initialize();

		if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {
			top  += parseFloat( jQuery.css(body, "marginTop") ) || 0;
			left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
		}

		return { top: top, left: left };
	},
	
	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" ) {
			elem.style.position = "relative";
		}

		var curElem = jQuery( elem ),
			curOffset = curElem.offset(),
			curCSSTop = jQuery.css( elem, "top" ),
			curCSSLeft = jQuery.css( elem, "left" ),
			calculatePosition = (position === "absolute" && jQuery.inArray('auto', [curCSSTop, curCSSLeft]) > -1),
			props = {}, curPosition = {}, curTop, curLeft;

		// need to be able to calculate position if either top or left is auto and position is absolute
		if ( calculatePosition ) {
			curPosition = curElem.position();
		}

		curTop  = calculatePosition ? curPosition.top  : parseInt( curCSSTop,  10 ) || 0;
		curLeft = calculatePosition ? curPosition.left : parseInt( curCSSLeft, 10 ) || 0;

		if ( jQuery.isFunction( options ) ) {
			options = options.call( elem, i, curOffset );
		}

		if (options.top != null) {
			props.top = (options.top - curOffset.top) + curTop;
		}
		if (options.left != null) {
			props.left = (options.left - curOffset.left) + curLeft;
		}
		
		if ( "using" in options ) {
			options.using.call( elem, props );
		} else {
			curElem.css( props );
		}
	}
};


jQuery.fn.extend({
	position: function() {
		if ( !this[0] ) {
			return null;
		}

		var elem = this[0],

		// Get *real* offsetParent
		offsetParent = this.offsetParent(),

		// Get correct offsets
		offset       = this.offset(),
		parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();

		// Subtract element margins
		// note: when an element has margin: auto the offsetLeft and marginLeft
		// are the same in Safari causing offset.left to incorrectly be 0
		offset.top  -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
		offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;

		// Add offsetParent borders
		parentOffset.top  += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
		parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;

		// Subtract the two offsets
		return {
			top:  offset.top  - parentOffset.top,
			left: offset.left - parentOffset.left
		};
	},

	offsetParent: function() {
		return this.map(function() {
			var offsetParent = this.offsetParent || document.body;
			while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
				offsetParent = offsetParent.offsetParent;
			}
			return offsetParent;
		});
	}
});

应用场景:
1: 使用position()方法时事实上是把该元素当绝对定位来处理,获取的是该元素相当于最近的一个拥有绝对或者相对定位的父元素的偏移位置
2: 使用position()方法时如果其所有的父元素都为默认定位(static)方式,则其处理方式和offset()一样,是当前窗口的相对偏移
3: 使用offset()方法不管该元素如何定位,也不管其父元素如何定位,都是获取的该元素相对于当前视口的偏移

参考:
http://www.cnblogs.com/believe3301/archive/2008/07/19/1246806.html
http://www.js8.in/602.html
http://article.qmecms.com/frontend/javascript/2010/07/18/jQuery,source,code,analysis,10,jquery,position-297.html
分享到:
评论

相关推荐

    理解Jquery 的offset与position方法

    在jQuery中,`offset()`和`position()`方法是用来获取元素位置的重要工具,它们的主要区别在于参考对象的不同。理解这两个方法的用法对于进行精确的页面布局和动态效果处理至关重要。 `offset()`方法返回的是匹配...

    Jquery中offset()和position()的区别分析

    在进行网页开发时,定位元素是经常需要进行的操作,而在JQuery中,offset()和position()是用于获取元素位置的两个主要方法。它们虽然在某些情况下可以提供相似的结果,但这两个方法在使用上存在本质的区别。了解它们...

    Jquery中的offset()和position()深入剖析

    先看看这两个方法的定义。 offset(): 获取匹配元素在当前视口的相对... 先来看看在jquery框架源码里面,是怎么获得position()的: 代码如下: // Get *real* offsetParent var offsetParent = this.offsetParent(), /

    jQuery Position方法使用和兼容性

    首先,我们来详细探讨Position方法与jQuery中的另一个常用方法offset()之间的区别。offset()方法用于获取元素相对于文档的当前位置,其返回值包含元素的top和left属性。然而,Position方法返回的是相对于最近的定位...

    jQuery中offset()方法用法实例

    在web前端开发中,jQuery是一个广泛使用的JavaScript库,它极大地简化了HTML文档遍历、事件处理、动画和Ajax交互等...通过本文的介绍和实例演示,相信读者已经能够对jQuery中offset()方法的用法有了较为深入的理解。

    jQuery.position()方法获取不到值的安全替换方法

    在jQuery中,获取元素位置的方法主要有两个:.position()和.offset()。.position()方法用于获取元素相对于其最近的已定位的父元素的位置,而.offset()方法则是获取相对于文档的绝对位置。然而,开发者在使用....

    js实现jquery的offset()方法实例

    原生JavaScript没有直接提供类似于offset()的便捷方法来直接获取元素的绝对偏移位置,但我们可以通过一些其他属性和方法来间接获得。在文档对象模型(DOM)中,每个DOM节点都有offsetParent属性,该属性指向最近的...

    jquery用offset()方法获得元素的xy坐标

    在实际应用中,offset()和position()方法可以根据需要获得不同类型的坐标信息。它们是前端开发中常用的工具,对于处理动画、交互效果等都非常有帮助。理解这两个方法之间的区别以及如何正确使用它们,对于进行网页...

    浅谈jQuery的offset()方法及示例分享

    offset() 方法是 jQuery 中的一个实用工具,用于获取或设置匹配元素相对于文档(document)的位置。它提供了一种便捷的方式来确定元素的当前坐标位置,或者动态调整元素的布局。 具体来说,offset() 方法可以分为...

    jQuery position() 函数详解以及jQuery中position函数的应用

    `jQuery.position()`函数是jQuery库中的一个重要方法,用于获取页面中元素相对于其最近的定位祖先元素(即CSS position属性设置为absolute、relative或fixed的祖先)的偏移坐标。这个函数对于实现精确的元素布局和...

    jQuery 常用方法

    本篇文章将深入探讨jQuery中的常用方法,基于jQuery 1.4版本进行总结,帮助开发者更好地理解和应用这些功能。 1. **选择器(Selectors)**:jQuery的选择器与CSS选择器相似,如`$("#id")`选取ID为id的元素,`$("....

    offset jquery

    在本篇文章中,我们将深入探讨一个与jQuery相关的代码片段,该片段主要关注于如何使用`offset()`方法来获取DOM元素的位置,并进一步利用这些位置信息来...希望本文能帮助你更好地理解和应用jQuery中的`offset()`方法。

    jquery根据锚点offset值实现动画切换

    在这篇文章的示例中,页面的主内容部分和背景部分都被设置为相对定位(position: relative),而且背景图片被设置为绝对定位(position: absolute),并且背景图片被放置在z轴的最底层(z-index: -5),以确保在滚动...

    jquery中有哪些api jQuery主要API

    首先,jQuery核心函数和方法是整个库的基石。`jQuery()`函数是jQuery库中最基本的函数,它允许开发者传入一个CSS选择器字符串来匹配一组DOM元素,并返回一个jQuery对象。这个对象使得链式操作成为可能。例如,使用`...

    jQuery 1.4.1 中文参考

    - `offset()`、`position()`、`scrollTop()`、`scrollLeft()`等:元素的位置和滚动信息。 - `height()`、`width()`、`innerHeight()`、`innerWidth()`、`outerHeight()`、`outerWidth()`:元素的尺寸计算。 **事件...

    JqueryApi中文手册

    **jQuery API 中文手册** jQuery 是一款广泛应用于前端开发的 JavaScript 库,它极大地简化了 JavaScript 的DOM操作、事件处理、动画制作以及...在实际开发中,结合实践与手册,可以更好地理解和掌握jQuery的精髓。

Global site tag (gtag.js) - Google Analytics