资讯专栏INFORMATION COLUMN

jQuery源码解析之offset()

keke / 2291人阅读

摘要:也就是说的本质为参数的属性减去对应的默认属性加上上的对应属性。所以的本质即相对于,对其,进行操作,而不是像那样相对于左上角原点进行操作这样就需要先减去中的的值了。

一、offset()

作用:
返回被选元素相对于文档(document)的偏移坐标

二、三种情况使用:

1、$().offset()



这是divTwo

源码:

   //返回目标元素相对于doucument的偏移坐标,
    //即距离浏览器左上角的距离

    // 返回偏移坐标:$(selector).offset()
    // 设置偏移坐标:$(selector).offset({top:value,left:value})
    // 使用函数设置偏移坐标:$(selector).offset(function(index,currentoffset))
    // offset() relates an element"s border box to the document origin
    //源码10500行
    //options即参数
    //arguments是参数对象
    offset: function( options ) {
      // Preserve chaining for setter
      //如果是有参数的,参数是undefined则返回目标元素本身,
      //否则为每个目标元素设置options
      console.log(options,arguments,"arguments10476")
      //$().offset()不走这里
      if ( arguments.length ) {
        console.log("aaa","vvv10507")
        return options === undefined ?
          this :
          this.each( function( i ) {
            //为每个目标元素设置options
            jQuery.offset.setOffset( this, options, i );
          } );
      }

      var rect, win,
        //获取DOM节点
        elem = this[ 0 ];

      if ( !elem ) {
        return;
      }

      // jQuery不支持获取隐藏元素的偏移坐标。
      // 同理,也无法取得隐藏元素的 border, margin, 或 padding 信息
      //所以如果元素是隐藏的,默认返回0值
      // Return zeros for disconnected and hidden (display: none) elements (gh-2310)
      // Support: IE <=11 only
      // Running getBoundingClientRect on a
      // disconnected node in IE throws an error
      //对IE的特殊处理
      if ( !elem.getClientRects().length ) {
        return { top: 0, left: 0 };
      }

      // Get document-relative position by adding viewport scroll to viewport-relative gBCR
      //返回元素的大小及其相对于视口的位置
      //https://developer.mozilla.org/zh-CN/docs/Web/API/Element/getBoundingClientRect
      rect = elem.getBoundingClientRect();
      //返回所属文档的默认窗口对象(只读)
      //原点坐标
      win = elem.ownerDocument.defaultView;
      //pageXOffset,pageYOffset 相当于 scrollX 和 scrollY 
      //返回文档在窗口左上角水平 x 和垂直 y 方向滚动的像素
      return {
        //16    0
        //
        top: rect.top + win.pageYOffset,
        //8     0
        left: rect.left + win.pageXOffset
      };
    },

解析:
由于$().offset()没有参数,所以源码里的两个 if 可以忽略,所以offset()的本质即:

  let p = document.getElementById("pTwo");
  let rect=p.getBoundingClientRect()
  //返回所属文档的默认窗口对象(只读)
  //原点坐标
  let win = p.ownerDocument.defaultView;
  let offsetObj={
    top: rect.top + win.pageYOffset,
    left: rect.left + win.pageXOffset
  }
  console.log(offsetObj,"win18")

(1)getBoundingClientRect()
该方法用于获取某个元素相对于视窗的位置集合,并返回一个对象,该对象中有top, right, bottom, left等属性,简单点就是相对于原坐标(默认是左上角)的偏移量

(2)window.pageXOffset、window.pageYOffset
返回文档在窗口左上角水平 x 和垂直 y 方向滚动的像素,相当于 scrollX 和 scrollY,简单点就是滚动的偏移量

所以offset()本质即:
相对于原坐标的偏移量+滚动的偏移量的总和。

2、$().offset({top:15,left:15})

$("#pTwo").offset({top:15,left:15})

源码:
当有参数的时候,就会走 if 中,通过jQuery.offset.setOffset( )来处理:

 if ( arguments.length ) {
        return options === undefined ?
          this :
          this.each( function( i ) {
            //为每个目标元素设置options
            jQuery.offset.setOffset( this, options, i );
          } );
      }

jQuery.offset.setOffset( )

  //offset()的关键方法
  //源码10403行
  jQuery.offset = {
    setOffset: function( elem, options, i ) {
      var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
        //获取元素的position属性的值
        //static
        position = jQuery.css( elem, "position" ),
        //过滤成标准jQuery对象
        curElem = jQuery( elem ),
        props = {};

      // Set position first, in-case top/left are set even on static elem
      //指定相对定位relative
      if ( position === "static" ) {
        elem.style.position = "relative";
      }
      //{left:8,top:16}
      curOffset = curElem.offset();
      //0px
      curCSSTop = jQuery.css( elem, "top" );
      //0px
      curCSSLeft = jQuery.css( elem, "left" );
      // 如果定位position是(绝对定位absolute或固定定位fixed),
      // 并且top,left属性包含auto的话
      //false
      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 {
        //0 0
        curTop = parseFloat( curCSSTop ) || 0;
        curLeft = parseFloat( curCSSLeft ) || 0;
      }
      //如果传的参数是function{}的话
      if ( isFunction( options ) ) {

        // Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
        options = options.call( elem, i, jQuery.extend( {}, curOffset ) );
      }
      //如果传的参数的有top值
      if ( options.top != null ) {
        //参数 top - offset().top + element.top
        props.top = ( options.top - curOffset.top ) + curTop;
      }
      //如果传的参数的有left值
      if ( options.left != null ) {
        //参数 left - offset().left + element.left
        props.left = ( options.left - curOffset.left ) + curLeft;
      }
      //自己没见过使用 using 的情况。。
      if ( "using" in options ) {
        options.using.call( elem, props );

      }
      //所以一般走这里,为当前元素设置top,left属性
      else {
        //position:relative
        //top:xxx
        //left:xxx
        curElem.css( props );
      }
    }
  };

解析:
(1)先判断当前元素的 position 的值,没有设置 position 属性的话,默认为 relative,并获取元素的 top、left 属性的值
(2)返回一个对象 obj,obj 的 top 是参数的 top - 默认偏移(offset)的 top + position 设置的 top(没有设置,默认为0),obj 的 left 同理。

也就是说 offset({top:15,;eft:15}) 的本质为:
参数的属性减去对应的默认offset属性加上position上的对应属性。

//伪代码
offset().top = elem. getBoundingClientRect().top + document. pageYOffset

top: offset({top:15}).top - offset().top + position.top
也就是:
offset({top:15}).top - (elem. getBoundingClientRect().top + document. pageYOffset) + position.top

3、$().offset(function(){})

  $("#pTwo").offset(function(index,currentoffset){
    let newPos={};
    newPos.left=currentoffset.left+15;
    newPos.top=currentoffset.top+15;
    return newPos;
  });

源码:

//如果传的参数是function{}的话
      if ( isFunction( options ) ) {
        // Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
        options = options.call( elem, i, jQuery.extend( {}, curOffset ) );
      }

解析:
让当前元素通过call 去调用参数中的 function(){} 方法,call 的参数必须一个一个放进去,上面源码中,call 参数有 i、jQuery.extend( {}, curOffset )

jQuery.extend( {}, curOffset )

暂不解析jQuery.extend() ,但这里的作用 不用看源码,也知道是将 element.offset() 的属性赋值给新建的空对象 {} 。

所以 $().offset(function(){}) 的本质即:相对于 element.offset() ,对其 top,left进行操作,而不是像 offset({top:xxx,left:xxx}) 那样相对于左上角原点进行操作(这样就需要先减去offset()中的top、left的值了)。

本文结束,五一愉快~

(完)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/104064.html

相关文章

  • jQuery源码解析position()

    摘要:注意的本质是的解析整体上看,是一个语句由于的元素,是相对于浏览器窗口进行定位的,所以它的偏移就是,即获取某个元素相对于视窗的位置。注意的本质是的完 showImg(https://segmentfault.com/img/remote/1460000019072306); position()作用:返回被选元素相对于父元素(parent)的偏移坐标 使用:直接调用$().positio...

    sunsmell 评论0 收藏0
  • 向Zepto学习关于"偏移"的那些事

    摘要:获得当前元素相对于的位置。返回一个对象含有和当给定一个含有和属性对象时,使用这些值来对集合中每一个元素进行相对于的定位。获取对象集合中第一个元素相对于其的位置。结尾以上就是中与偏移相关的几个的解析,欢迎指出其中的问题和有错误的地方。 前言 这篇文章主要想说一下Zepto中与偏移相关的一些事,很久很久以前,我们经常会使用offset、position、scrollTop、scrollLe...

    hzx 评论0 收藏0
  • 由一个“bug”到鲜为人知的jQuery.cssHooks

    摘要:干想了半天,认为可能还是本身的写法问题。对象提供了一种通过定义函数来获取或设置特定值的方法。简单来说,给我们暴露了一个钩子,我们可以自己定义方法比如,来实现针对某个属性的特定行为。 写在最前 本次分享一下在一次jQuery赋值样式失效的结果中来分析背后原因的过程。在翻jQuery源码的过程中,感觉真是还不能说自己只是会用jQuery,我好像连会用都达不到(逃 欢迎关注我的博客,不定期更...

    ernest.wang 评论0 收藏0
  • 由一个“bug”到鲜为人知的jQuery.cssHooks

    摘要:干想了半天,认为可能还是本身的写法问题。对象提供了一种通过定义函数来获取或设置特定值的方法。简单来说,给我们暴露了一个钩子,我们可以自己定义方法比如,来实现针对某个属性的特定行为。 写在最前 本次分享一下在一次jQuery赋值样式失效的结果中来分析背后原因的过程。在翻jQuery源码的过程中,感觉真是还不能说自己只是会用jQuery,我好像连会用都达不到(逃 欢迎关注我的博客,不定期更...

    malakashi 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<