`
jljlpch
  • 浏览: 319789 次
  • 性别: Icon_minigender_1
  • 来自: 南昌
社区版块
存档分类
最新评论

jquery position

阅读更多
5.2.3 position     
                               prk/彭仁夔   08-08-25
在给元素定位之前,我们首先要了解一些CSS定位相关的知识。
在CSS中关于定位的内容是:position:relative | absolute | static | fixed 。static 没有特别的设定,遵循基本的定位规定,不能通过z-index进行层次分级。relative 不脱离文档流,参考自身静态位置通过 top,bottom,left,right 定位,并且可以通过z-index进行层次分级。absolute 脱离文档流,通过 top,bottom,left,right 定位。选取其最近的父级定位元素,当父级 position 为 static 时,absolute元素将以body坐标原点进行定位,可以通过z-index进行层次分级。
fixed 固定定位,这里他所固定的对像是可视窗口而并非是body或是父级元素。可通过z-index进行层次分级。CSS中定位的层叠分级:z-index: auto | namber
relative | absolute | static | fixed这四种定位的方式不一样,我们要找到元素的位置的方法也会随之不一样。
Dom元素提供了三种方式来定位元素:offset,scroll,Client,
 
图 转自(http://www.cnblogs.com/believe3301/archive/2008/07/19/1246806.html)
Dom元素对于offset提供了offsetParent、offsetTop、offsetLeft、offsetWidth、offsetHeight五个方法来定位于元素的相对位置。
offsetParent是指当前元素的相对定位的元素。在IE和FF中定义和解释不一样。在IE中定义为获取定义对象 offsetTop 和 offsetLeft 属性的容器对象的引用。大多数时候offsetParent返回body元素。在IE5中,td的offsetParent是table。可以看出IE中的相对定位与绝对定位的区别不大。都是相对于最上层的元素来定位。在FF中获取文档层次中最近的元素。如果这个元素没有定位,那么就根元素。
offsetParent、parentNode(IE:parentElement)都是指元素的父节点。它们的针对的目标是不一样,功能也不一样。parentNode就是取文档层次中包含该节点的最近节点(直接的父节点)。在FF中对于Attr, Document, DocumentFragment, Entity,和Notation这些父节点,其 parentNode返回null。还有如果没有附加到文档树的元素也是返回null。
   offsetParent是指可视的父节点。如 <body><form><input type=’’’text’ id=’AA’/></form></body>。AA的offsetParent是body,而parentNode则是form。在IE中一般都是body。
offsetLeft和offsetTop是指当前元素left或top边到offsetParent的left或top边的距离,包含了当前元素的margin和其offsetParent的padding。不包含offsetParent的border的宽度。
offsetWidth、offsetHeight与offsetLeft、offsetTop的相对offsetParent的方式不一样,它们就是当前元素自身的宽度或高度。它包含border、padding、scrollBar(显示的话)和内容的size(CSS中设定的元素的高度,IE中CSS size指的是包含border的内容大小)。
分析了offset,我们可以发现offsetLeft、offsetTop与CSS中top,left的属性有相通性,offsetLeft、offsetTop只能取值。而我们可以通过CSS中top,left的属性来设定一个元素的相对其它元素的位置(绝对定位,就是相对于body)。

 Dom元素对于scroll提供了scrollWidth、scrollHeigth、scrollTop、scrollLeft。这一组是对于scroll的元素进行操作的。Scroll的Width、Heigth是指元素真实的宽度和高度,它包含被scroll起来的部分。而scrollTop、scrollLeft则是被卷起来的部分的大小。
 Dom元素对于scroll提供了clientWidth、clientHeigth、clientTop、clientLeft。这一组是对于client进行操作的。clientWidth、clientHeigth是元素的内容可视区域的高度或宽度。包含padding,不包含scrollbar 、border、margin。可以看出是元素可视的区域。IE,FF是一样的。clientTop、clientLeft可以看做是topborder或left border的大小。

offsetParent的名字的元素能计算相对位移的父节点,那么对于CSS的定位方式,哪一些是可以计算位移呢,能计算元素和其父节点之间的位移量,首先要其父节点能定位。这个定位就是在CSS中能采用top,left来定其在文档的位置。Body是肯定可以的(0,0)。Body也是元素的终结offsetParent(没有找到就是它了),absolute、 relative、 fixed都采用可以top,left来定其在文档的位置。也是能计算其位置。而static是不需要top,left来设定其位置, Offset是相对已经定位的元素的位移。元素的offsetParent是其父辈节点中的postiont!= Static的节点。在IE中http://msdn.microsoft.com/zh-cn/library/system.windows.forms.htmlelement.offsetparent(VS.80).aspx,可以看到其不支持fixed的offsetParent。在mozilla中http://developer.mozilla.org/en/DOM/element.offsetParent,可以看出其给出的如果元素没有定位(non-positioned)就是body。
Jquery针对于offsetParent提供了一个改进的方法。它还是在浏览器的offsetParent基础之上多加了一个判断的处理,筛选其有可能会是static的节点。觉得这样做的意义不大。除了table,tr,td之外,浏览器的offsetParent是body的可能性很大。这是一个不确定的。在使用中是要注意的。
//找到this[0]中元素第一个能根据CSS中的top,left能设定位置的父辈节点。
	offsetParent: function() {
		var offsetParent = this[0].offsetParent || document.body;
	while ( offsetParent && (!/^body|html$/i.test(offsetParent.tagName) 
&& jQuery.css(offsetParent, 'position') == 'static') )
		offsetParent = offsetParent.offsetParent;
		return jQuery(offsetParent);
	}

其实觉得最好的方法还是直接相对于body的来定位。这样的定位是确定的。但是浏览器在计算这个值会有点问题,而且每种浏览器的实现方式不一样,很难兼容。Jquery提供了一个相对于文档的起始位置的offset方法。

//元素相对于文档的起始位置的offset
jQuery.fn.offset = function() {
	var left = 0, top = 0, elem = this[0], results;
	if ( elem ) with ( jQuery.browser ) {
		var parent    = elem.parentNode,    offsetChild  = elem,
		  offsetParent = elem.offsetParent,
		 doc       = elem.ownerDocument,
		 safari2   = safari && parseInt(version) < 522 
&& !/adobeair/i.test(userAgent),
	   css          = jQuery.curCSS,
	   fixed        = css(elem, "position") == "fixed";

 //在IE中有的元素可以通过getBoundingClientRect来获得元素相对于client的rect.
if ( !(mozilla && elem == document.body) && elem.getBoundingClientRect ) {//IE  http://msdn.microsoft.com/en-us/library/ms536433.aspx    ①
	var box = elem.getBoundingClientRect();
	// 加上document的scroll的部分尺寸到left,top中。
	add(box.left + Math.max(
doc.documentElement.scrollLeft, doc.body.scrollLeft),
		box.top  + Math.max(
doc.documentElement.scrollTop,  doc.body.scrollTop));
            //IE中会自动加上2px的border,这里是去掉document的边框大小。
			//http://msdn.microsoft.com/en-us/library/ms533564(VS.85).aspx
	/The difference between the offsetLeft and clientLeft properties
// is the border of the object
	add( -doc.documentElement.clientLeft, 
-doc.documentElement.clientTop );
	} else {                                                               ②
//通过遍历当前元素offsetParents来计算其在文档中的位置(相对于文档的起始位置)
	add( elem.offsetLeft, elem.offsetTop );//初始化元素left,top	  ③		 //很多浏览器的offsetParent是直接指向body。不过有的是指向最近的可视的父节点。
	while ( offsetParent ) {	//加上父节点的偏移			            
		add( offsetParent.offsetLeft, offsetParent.offsetTop );	 ④		 // Mozilla系列offsetLet或offsetTop不包含offsetParent的边框。要加上
	 //但在在table中又会自动加上。
	   if ( mozilla && !/^t(able|d|h)$/i.test(offsetParent.tagName)
 || safari && !safari2 )
		border( offsetParent );//增加offsetParent的border          ⑤
	  // 对于CSS设定为fixed相对于client的定位,加上document.scroll.
	  if ( !fixed && css(offsetParent, "position") == "fixed" )
					fixed = true;
	  //改变子节点变量offsetChild,再改变offsetParent变量的指向。
	   offsetChild  = /^body$/i.test(offsetParent.tagName) ? 
offsetChild : offsetParent;				
	     	offsetParent = offsetParent.offsetParent;
		}
	// 减去处理每一层不显示的scroll的部分。
	// 因为一个元素的size(CSS中指定的)是scroll之前的。
	// 如果scroll,offsetLet或offsetTop会包含这部分被卷起的。			
	while ( parent && parent.tagName 
&& !/^body|html$/i.test(parent.tagName) ) {       ⑥
	// 如果parent的display的属性不为inline|table,减去它的scroll.			if ( !/^inline|table.*$/i.test(css(parent, "display")) )
		// 减去 parent scroll offsets
		add( -parent.scrollLeft, -parent.scrollTop );
		// 如果overflow != "visible.在Mozilla 中就不会加上border.s
		if ( mozilla && css(parent, "overflow") != "visible" )
				border( parent );				
			parent = parent.parentNode;
			}
			
	//Safari <= 2,在CSS中position为fiexed或者body的position==absolute,
	//会重复加上body offset。Mozilla在Position!=absolute的时候也会重复
if ( (safari2 && (fixed || css(offsetChild, "position") == "absolute")) 
 ||	(mozilla && css(offsetChild, "position") != "absolute") )
	add( -doc.body.offsetLeft, -doc.body.offsetTop );              ⑦
					
	//fixed 加上document scroll。
//因为fixed是scroll的时候也是相对于client不变。所以要加上
	if ( fixed )                                                         ⑧
	add(Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
		Math.max(doc.documentElement.scrollTop,  doc.body.scrollTop));	}		
	results = { top: top, left: left };
}
function border(elem) {
		add( jQuery.curCSS(elem, "borderLeftWidth", true), jQuery.curCSS(elem, "borderTopWidth", true) );
	}
function add(l, t) {
		left += parseInt(l, 10) || 0;
		top += parseInt(t, 10) || 0;
	}
return results;
};
上面的代码①采用IE内部提供了特有的方法来找到相对body的Offset。这样做肯定是提高在IE中效率。②③④⑤⑥⑦⑧处是采用通用的处理方法来计算。对于一个元素的offset,加上其所有offsetParent的offset和border。这样就能计算出相对于body的offset。但是这样在scroll的情况下是行不通的。因为有scroll的卷起来的部分也被计算了进去,对于每个元素都要减去这一部分的大小。
⑧处我们可以看出如果有元素是fixed的position。说明其会随着documentElement.scroll而改变位置。因此加上documentElement.scroll。得出其正确的位置。

Jquery中的position方法是计算当前元素相对于其offsetParent的offset值。与dom元素的offset不一样的地方,它是建立在jquery.offset的基础之上,同时还不包括其自身的margin。对于box的模式来讲,是margin是元素的最外边,而不是border。
jQuery.fn.extend({position: function() {
	var left = 0, top = 0, results;
	if ( this[0] ) {		
		var offsetParent = this.offsetParent(),// Get *real* offsetParent
		  offset   = this.offset(),// Get correct offsets
		parentOffset = /^body|html$/i.test(offsetParent[0].tagName)
 ? { top: 0, left: 0 } : offsetParent.offset();
			offset.top  -= num( this, 'marginTop' );
			offset.left -= num( this, 'marginLeft' );
			parentOffset.top  += num( offsetParent, 'borderTopWidth' );
			parentOffset.left += num( offsetParent, 'borderLeftWidth' );
			results = {
				top:  offset.top  - parentOffset.top,
				left: offset.left - parentOffset.left
			};
		}
		return results;
	},

Jquery还提供了两个关于scroll的方法, scrollLeft and scrollTop:
// Create scrollLeft and scrollTop methods
jQuery.each( ['Left', 'Top'], function(i, name) {
	var method = 'scroll' + name;	
	jQuery.fn[ method ] = function(val) {
		if (!this[0]) return;
		return val != undefined ? 	// Set the scroll offset
			this.each(function() {
				this == window || this == document ?
					window.scrollTo(
						!i ? val : jQuery(window).scrollLeft(),
						 i ? val : jQuery(window).scrollTop()
					) :
					this[ method ] = val;
			}) : // Return the scroll offset

			this[0] == window || this[0] == document ?
				self[ i ? 'pageYOffset' : 'pageXOffset' ] ||
					jQuery.boxModel && document.documentElement[ method ] 
||document.body[ method ] :
				this[0][ method ];
	};

 

分享到:
评论
1 楼 zxc005 2009-01-25  
谢谢,分析地很细致!

相关推荐

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

    position()函数用于返回当前匹配元素相对于其被定位的祖辈元素的偏移,也就是相对于...该函数只对可见元素有效,通过本文给大家介绍jQuery position() 函数详解以及jQuery中position函数的应用,感兴趣的朋友一起学习吧

    jQuery Position方法使用和兼容性

    position方法获取匹配元素相对父元素的偏移。接下来通过本文给大家分享jQuery Position方法使用和兼容性的相关知识,感兴趣的朋友一起看看吧

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

    主要介绍了jQuery.position()方法获取不到值的安全替换方法,本文给出了一种变通的方法,用.offset()来换算,需要的朋友可以参考下

    理解Jquery 的offset与position方法

    理解Jquery 的offset与position方法

    jQuery 1.4.1 中文参考

    7.2.3 position() 111 7.2.4 scrollTop() 111 7.2.5 scrollTop(val) 111 7.2.6 scrollLeft() 112 7.2.7 scrollLeft(val) 112 7.3 尺寸 113 7.3.1 height() 113 7.3.2 height(val) 113 7.3.3 width() 114 7.3.4 width...

    Jquery插件下拉复选multiSelect使用

    NULL 博文链接:https://javah-h.iteye.com/blog/2111356

    JQuery新版中文手册

    position() scrollTop([val]) scrollLeft([val]) 尺寸 heigh([val|fn]) width([val|fn]) innerHeight() innerWidth() outerHeight([soptions]) outerWidth([options]) 选择器 基本 #id element .class...

    jQuery帮助文档

    position() scrollTop( [val] ) scrollLeft( [val] ) 尺寸 height( [val] ) width( [val] ) innerHeight() innerWidth() outerHeight(options) outerWidth(options) 选择器 基本 #id element .class * ...

    Jquery学习手册

    jQuery.eq(position),获取jQuery对象集合中的一个jQuery对象 3、Data相关方法 jQuery.data(name) jQuery.data(name, value) jQuery.removeData(name) 4、选择符 multiple(selector1, selector2),可以选择多...

    jquery插件使用方法大全

    Jquery是继prototype之后又一个优秀的Javascrīpt框架。它是轻量级的js库(压缩后只有21k) ,它兼容CSS3,还兼容各种浏览器 (IE 6.0+, FF 1.5+, Safari 2.0+, Opera 9.0+)。jQuery使用户能更方便地处理...

    jQuery UI插件

    主要用于便捷的网页弹框开发,引用方法如下:(可参考... &lt;script type="text/javascript" src="ui/jquery.ui.position.js"&gt; &lt;script type="text/javascript" src="ui/jquery.ui.dialog.js"&gt;&lt;/script&gt;

    jQuery 1.5 API 中文版

    obj.position( ) int.scrollTop( ) $.scrollTop( val ) int.scrollLeft( ) $.scrollLeft( val ) Height and Width int.height( ) $.height( val ), .height( fn(index, height ) ) int.width( ) $.width( val ), ....

    jQuery中position()方法用法实例

    主要介绍了jQuery中position()方法用法,实例分析了position()方法的功能、定义及获取匹配元素相对某些元素的偏移量时的使用技巧,需要的朋友可以参考下

    jQuery的position()方法详解

    position()函数用于返回当前匹配元素相对于其被定位的祖辈元素的偏移,也就是相对于被定位的祖辈元素的坐标。该函数只对可见元素有效。

    JQuery UI/API/1.7 中文帮助文档

    JQuery UI/API/1.7 中文帮助文档 ...ui.position - 辅助对象相对于上级元素的当前位置, 使用{ top, left } ui.offset - 辅助对象相对于页面的当前绝对位置, 使用{ top, left } 其他附加文件 UI Core 示例

    最新jquery easyUI中文文档 1.5版本没有之一

    所有的属性都定义在jQuery.fn.{plugin}.defaults里面。例如,对话框属性定义在jQuery.fn.dialog.defaults里面。 事件 所有的事件(回调函数)也都定义在jQuery.fn.{plugin}.defaults里面。 方法 调用方法的语法:$...

    jquery文件

    jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.position.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.tabs.js * Copyright (c) 2012 AUTHORS.txt; Licensed MIT */

    JQuery对元素拖拽排序,元素拖拽,JQuery拖拽Demo

    用JQuery写的拖动元素进行排序的方法,包含拖动排序、拖动移除、拖动添加。 代码完整可用。没有用到第三方插件,自主可控。 原理是用CSS中position定位来跟踪鼠标移动,就是让元素跟踪鼠标位置,然后判断其在页面...

Global site tag (gtag.js) - Google Analytics