首先是原型上的offset方法,根据arguments判断到底是取值还是设值。如果是设置,就遍历调用静态方法jQuery.offset.setOffset

如果是取值。那么就是从"var docElem,win"这里开始了。

jQuery.fn.offset = function( options ) {
if ( arguments.length ) {//设置元素坐标
return options === undefined ?//如果传入的参数是undefined,直接返回
this :
this.each(function( i ) {//遍历然后调用jQuery.offset.setOffset
jQuery.offset.setOffset( this, options, i );
});
} var docElem, win,
elem = this[ 0 ],
box = { top: 0, left: 0 },
doc = elem && elem.ownerDocument;//当前文档 if ( !doc ) {
return;
} docElem = doc.documentElement; // Make sure it's not a disconnected DOM node
if ( !jQuery.contains( docElem, elem ) ) {//如果元素没有被documentElement包含,就返回 0 0
return box;
} // If we don't have gBCR, just use 0,0 rather than error
// BlackBerry 5, iOS 3 (original iPhone)
if ( typeof elem.getBoundingClientRect !== core_strundefined ) {//如果元素有getBoundingClientRect方法
box = elem.getBoundingClientRect();//调用该方法
} win = getWindow( doc );//如果是window就返回window,如果是document,返回document.defaultView
return {
//元素相对于视窗的距离+滚动距离-边框宽度
top: box.top + win.pageYOffset - docElem.clientTop,
left: box.left + win.pageXOffset - docElem.clientLeft
};
};

取值中,它考虑了元素没有被documentElement包含的情况,没有渲染,自然是没有offset的,于是它很神奇的返回了{"top":0,"left":0}。

因为看的是jQuery 2.x的版本,这里它用到了getBoundingClientRect方法,从名字就可以看出,它返回的是相对于视窗的距离,这不是我们需要的offset,jQuery.offset返回的是相对于文档的距离,所以还要做进一步的计算:

    return {
//元素相对于视窗的距离+滚动距离-边框宽度
top: box.top + win.pageYOffset - docElem.clientTop,
left: box.left + win.pageXOffset - docElem.clientLeft
};

关于getWindow,看看函数声明:

function getWindow( elem ) {
return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;
}

如果elem是window,直接返回window,如果是document,则返回document.defaultView。

不是很理解为什么要使用document.defaultView,群里的小伙伴说可能是多frame的情况

然后我在stackoverflow上找到的帖子 http://stackoverflow.com/questions/9183555/whats-the-point-of-document-defaultview 也有类似的答案,然后另一种可能是为了修复Firefox 3.6中getComputedStyle的bug(⊙o⊙)…

接下来是静态方法设置offset。。。

jQuery.offset = {

    setOffset: function( elem, options, i ) {
var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
position = jQuery.css( elem, "position" ),//获取当前元素的position属性
curElem = jQuery( elem ),//缓存当前元素
props = {}; // Set position first, in-case top/left are set even on static elem
if ( position === "static" ) {//如果原元素是静态定位的,改成相对定位
elem.style.position = "relative";
} curOffset = curElem.offset();//获取当前元素的offset
curCSSTop = jQuery.css( elem, "top" );
curCSSLeft = jQuery.css( elem, "left" );
//如果元素的position为absolute或者fixed,而且其top和left属性中至少有一项的值是auto,calculatePosition为true
calculatePosition = ( position === "absolute" || position === "fixed" ) && ( curCSSTop + curCSSLeft ).indexOf("auto") > -1; // Need to be able to calculate position if either top or left is auto and position is either absolute or fixed
if ( calculatePosition ) {
curPosition = curElem.position();//获取元素相对于父元素的偏移位置
curTop = curPosition.top;
curLeft = curPosition.left; } else {//如果calculatePosition为false,元素相对定位或者原本就有top、left值
curTop = parseFloat( curCSSTop ) || 0;
curLeft = parseFloat( curCSSLeft ) || 0;
} if ( jQuery.isFunction( options ) ) {//如果options是函数,遍历调用
options = options.call( elem, i, curOffset );
}
//计算props值,因为offset是相对文档定位,新的css的top/left值
//需要根据原来的offset和css的top/left值计算
if ( options.top != null ) {
props.top = ( options.top - curOffset.top ) + curTop;
}
if ( options.left != null ) {
props.left = ( options.left - curOffset.left ) + curLeft;
}
//如果有using这个参数,可以调用using方法
if ( "using" in options ) {
options.using.call( elem, props ); } else {//如果没有,设置css偏移。
curElem.css( props );
}
}
};

关于using这个选项,之前在jQuery API中没有看到过。发现隐藏技能了(⊙o⊙)…??

好吧,刚在百度上试了下

$('#page').offset({"top":1000,"left":100,"using":function(prop){console.log(prop)}});
//Object {top: -302, left: 100}

jQuery offset()源码解析的更多相关文章

  1. jquery 部分函数源码解析

    JSON.stringify源码(在看extend文档的时候看到) var object1 = { apple: 0, banana: {weight: 52, price: 100}, cherry ...

  2. jquery extend源码解析

    $.extend(obj1,0bj2,{"name":"s","age":22}) //target 要拷贝到哪个对象上 // i 要执行拷 ...

  3. jQuery源码解析资源便签

    最近开始解读jQuery源码,下面的链接都是搜过来的,当然妙味课堂 有相关的一系列视频,长达100多期,就像一只蜗牛慢慢爬, 至少品读三个框架,以后可以打打怪,自己造造轮子. 完全理解jQuery源代 ...

  4. jquery源码解析:代码结构分析

    本系列是针对jquery2.0.3版本进行的讲解.此版本不支持IE8及以下版本. (function(){ (21, 94)     定义了一些变量和函数,   jQuery = function() ...

  5. jQuery整体架构源码解析(转载)

    jQuery整体架构源码解析 最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性, ...

  6. JQuery源码解析(一)

    写在前面:本<JQuery源码解析>系列是基于一些前辈们的文章进行进一步的分析.细化.修改而写出来的,在这边感谢那些慷慨提供科普文档的技术大拿们. 要查阅JQ的源文件请下载开发版的JQ.j ...

  7. jquery 源码解析

    静态与实力方法共享设计 遍历方法 $(".a").each() //作为实例方法存在 $.each() //作为静态方法存在 Jquery源码 jQuery.prototype = ...

  8. jQuery 源码解析二:jQuery.fn.extend=jQuery.extend 方法探究

    终于动笔开始 jQuery 源码解析第二篇,写文章还真是有难度,要把自已懂的表述清楚,要让别人听懂真的不是一见易事. 在 jQuery 源码解析一:jQuery 类库整体架构设计解析 一文,大致描述了 ...

  9. jQuery整体架构源码解析

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

随机推荐

  1. shell动态变量

    面对变量中嵌套变量,可以这么做 other_devops_ip="......." options='_ip' tennat_name='other_devops' tennat_ ...

  2. top命令按内存和cpu排序

    目录 按进程的CPU使用率排序 按进程的内存使用率排序 按进程的CPU使用率排序 运行top命令后,键入大写P. 有两种途径: a) 打开大写键盘的情况下,直接按P键 b) 未打开大写键盘的情况下,S ...

  3. iPhone HTTP获得XML并使用GDataXML解析

    1. [代码][C/C++]代码     NSURL *url = [NSURL URLWithString:  @"http://www.raywenderlich.com/downloa ...

  4. Peach+Fuzzer

    目录 1 Peach是什么....................................................................................... ...

  5. Hibernate 模糊查询 ' %?% ' SQL执行异常

    今天我在使用Hibernate 的SQL预编译之后注入参数的形式写了一条模糊查询语句.刚开始我是这么写的

  6. Android Dalvik虚拟机

    虽然Android平台使用Java来开发应用程序,但Android程序却不是运行在标准Java虚拟机上的. 可能是出于效率和版权的考虑,Google为Android专门设计了一套虚拟机Dalvik V ...

  7. Swift类型转换

    关于「类型转换」(Type Casting),<The Swift Programming Language>描述如下: Type casting is a way to check th ...

  8. kafka数据可靠性深度解读【转】

    1 概述 Kakfa起初是由LinkedIn公司开发的一个分布式的消息系统,后成为Apache的一部分,它使用Scala编写,以可水平扩展和高吞吐率而被广泛使用.目前越来越多的开源分布式处理系统如Cl ...

  9. 修改SQL Server 2005的默认端口

    修改SQL Server 2005的默认端口 1.打开SQL Server的配置管理程序 Microsoft SQL Server 2005->配置工具->SQL Server Confi ...

  10. js正则匹配字符串

    这里我第一时间想到的就是用 js 的search 和 match ,其中最常见的是match: 1. str.search(regexp):search()方法不支持全局搜索,因为会忽略正则表达式参数 ...