• jQuery2.0.3源码分析系列(28) 元素大小


    最近的分析都是有点不温不火,基本都是基础的回顾了

    今年博客的目标目前总的来说有2大块

    JS版的设计模式,会用jQuery来诠释

    JS版的数据结构,最近也一直在狠狠的学习中.

    HTML息息相关的的样式

    偏移量

    offsetWidth offsetHeight offsetLeft offsetTop

    image

    offsetHeight/offsetWidth: 表述元素的外尺寸:元素内容+内边距+边框(不包括外边距)

    offsetLeft/offsetTop: 表示该元素的左上角(边框外边缘)与已定位的父容器(offsetParent对象)左上角的距离。

    offsetParent元素是指元素最近的定位(relative,absolute)祖先元素,可递归上溯。


    客户区大小

    clientWidth clientHeight 

    image

    clientWidth/clientHeight: 用于描述元素的内尺寸:元素内容+两边内边距


    滚动大小

    scrollWidth scrollHeight scrollLeft scrollTop

    image

    scrollHeight/scrollWidth: 元素内容的总高度或宽度

    scrollLeft/scrollTop:是指元素滚动条位置,它们是可写的(被隐藏的内容区域左侧/上方的像素)

    浏览器窗口的滚动条位置:window对象的pageXoffset和pageYoffset, IE 8及更早版本可以通过scrollLeft和scrollTop属性获得滚动条位置


    以下是网上的总结,我收集下

    Chrome/FF/Safari/opera
    对这些浏览器而言,window有个属性innerWidth/innerHeight包含的是整个文档的可视区域尺寸,注意,这个尺寸是包含滚动条大小的。
    如果我们不计滚动条的影响,就可以直接使用这两个属性。
    如果滚动条会影响(比如最大化弹出框),那么应该想另外的办法。

    document.documentElementy与document.body

    Document对象是每个DOM树的根,但是它并不代表树中的一个HTML元素,document.documentElement属性引用了作为文档根元素的html标记,document.body属性引用了body标记
    我们这里获取常见的三个值(scrollWidth、offsetWidth和clientwidth)来比较一下

    document.documentElement.scrollWidth返回整个文档的宽度
    document.documentElement.offsetWidth返回整个文档的可见宽度
    document.documentElement.clientwidth返回整个文档的可见宽度(不包含边框),clientwidth = offsetWidth - borderWidth

    不过一般来说,我们不会给document.documentElement来设置边框,所以这里的clientwidth 与 offsetWidth一致

    document.body.scrollWidth返回body的宽度
    注意,这里的scrollWidth有个不一致的地方,基于webkit的浏览器(chrome和safari)返回的是整个文档的宽度,也就是和document.documentElement.scrollWidth一致,
    opera和FF返回的就是标准的body 的scrollWidth,个人觉得opera和FF算是比较合理的。


    document.body.offsetWidth返回body的offsetWidth
    document.body.clientwidth返回body的clientwidth(不包含边框),clientwidth = offsetWidth - borderWidth

    我们看上面的例子,会发现

    body和documentElement的有些值是相等的,这并不是表示他们是等同的。而是因为当我们没有给body设置宽度的时候,document.body默认占满整个窗口宽度,

    于是就有:

    document.body.scrollWidth = document.documentElement.scrollWidth
    document.body.offsetWidth = document.documentElement.offsetWidth
    document.body.clientwidth = document.documentElement.clientwidth - document.body.borderWidth(body的边框宽度)


    当我们给body设置了一个宽度的时候,区别就出来了。

    IE9/IE8
    这两个差不多,唯一的区别是IE9包含window.innerWidth属性,而IE8不包含window.innerWidth属性。
    document.documentElement.scrollWidth返回整个文档的宽度,和FF等浏览器一致
    document.documentElement.offsetWidth返回整个文档的可见宽度(包含滚动条,值和innerWidth一致),注意,这里和FF等浏览器又有点区别。
    document.documentElement.clientwidth返回整个文档的可见宽度(不包含边框),和FF等浏览器一致。clientwidth = offsetWidth - 滚动条宽度

    document.body.scrollWidth返回body的宽度,注意,这里的scrollWidth和FF等浏览器有点区别,这里并不包括body本身的border宽度。
    因此例子中,相比FF少了10px。
    document.body.offsetWidth返回body的offsetWidth,和FF等浏览器一致
    document.body.clientwidth返回body的clientwidth(不包含边框),和FF等浏览器一致,clientwidth = offsetWidth – borderWidth

    IE7与IE9/IE8的主要区别是
    第一、document.documentElement.offsetWidth的返回值不一样,
    参见上面说的,IE9/IE8的document.documentElement.offsetWidth包含滚动条,但是,IE7的document.documentElement.offsetWidth不包含滚动条。
    第二、document.documentElement.scrollWidth返回整个文档的宽度,注意,这里和IE9/IE8、FF等浏览器又有不一致,对于IE9/IE8、FF等浏览器,scrollWidth最小不会小于窗口的宽度,但是在IE下没有这个限制,文档有多小,这个就有多小
    其他倒是挺一致的。

    IE6了
    IE6的document.documentElement返回值与IE9/IE8没有区别(由此可见,对于document.documentElement,IE7就是个奇葩)。
    话说回来,IE的document.body就是个奇葩,当没有给body设置宽度的时候,body是默认占满整个文档的(注意,其他的浏览器都是占满整个窗口),当然,最小值是整个窗口的大小,就是说body指向了根元素。
    因此,在算上IE6在解析width方面的bug,和其他的浏览器的区别就淋漓尽致了。
    document.body.scrollWidth返回body的宽度,和IE9/IE8/IE7一致
    document.body.offsetWidth返回body的offsetWidth,注意,由于body的不同,这里的offsetWidth = scrollWidth + borderWidth
    document.body.clientwidth返回body的clientwidth(不包含边框)clientwidth = offsetWidth - borderWidth
    另外,有一点和IE7同样,就是document.documentElement.scrollWidth没有最小宽度限制。


    源码解析

    先看jQuery对窗口大小六种相似方法的生成

     

    jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
            jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
          
    //执行代码
            });
        });

    扩展方法还是用的合并的模式,把具有相同特性的方法采用合并处理

    循环生成是艺术,需要深刻了解它们的功能与共同点,然后将特异点组成一个对象,好处自然是省代码了,然后可以集中处理

     

    执行代码

    例如:.width()

    为匹配的元素集合中获取第一个元素的当前计算宽度值。

    return jQuery.access( this, function( elem, type, value ) {
        var doc;
        if ( jQuery.isWindow( elem ) ) {
            return elem.document.documentElement[ "client" + name ];
        }
    
        // Get document width or height
        if ( elem.nodeType === 9 ) {
            doc = elem.documentElement;
            return Math.max(
                elem.body[ "scroll" + name ], doc[ "scroll" + name ],
                elem.body[ "offset" + name ], doc[ "offset" + name ],
                doc[ "client" + name ]
            );
        }
    
        return value === undefined ?
            jQuery.css( elem, type, extra ) :
            jQuery.style( elem, type, value, extra );
    }, type, chainable ? margin : undefined, chainable, null );

     

    A.首先先解释下普通元素和非普通元素,

    非普通元素是指window,document这些 元素对象,

    普通元素是指除window,document之外的元素,如:div

    B.css(width) 和 .width()之间的区别?

    • 对于非普通元素,只能使用 .width()

    • 对于普通的元素 ,他们的作用相同

    • 后者返回一个没有单位的数值(例如,400),前者是返回带有完整单位的字符串(例如,400px)。当一个元素的宽度需要数学计算的时候推荐使用.width() 方法

      C.非普通元素的获取

      如:window

      $(window).width();   //浏览器窗口
      即返回HTML的窗口,所以代码就是document.documentElement[“clientWidth”]
      if ( jQuery.isWindow( elem ) ) {
              return elem.document.documentElement[ "client" + name ];
          }
       
      document
      $(document).width();   //HTML文档窗口

      取最大值,因为可以带卷滚条溢出

      if ( elem.nodeType === 9 ) {
          doc = elem.documentElement;
      
          // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
          // whichever is greatest
          return Math.max(
              elem.body[ "scroll" + name ], doc[ "scroll" + name ],
              elem.body[ "offset" + name ], doc[ "offset" + name ],
              doc[ "client" + name ]
          );
      }
       

      D.普通元素取值

      jQuery.cssHooks

      因为有些样式不是简单的读写属性就可以的,比如width就不是简单地读取el.style.width。为了解决这个问题,jquery定义了一个属性 $.cssHooks,这里可以自定义对某个属性的get和set操作。而且jquery中就是用cssHooks来处理某些特殊属性的

      对CSS的操作都是通过统一的API调用,操作的属性是

      1. borderWidth: Object
      2. height: Object
      3. margin: Object
      4. opacity: Object
      5. padding: Object
      6. Object

      此时就会用jQuery.cssHooks方法处理兼容问题,

      width,height的钩子方法

      jQuery.each([ "height", "width" ], function( i, name ) {
              jQuery.cssHooks[ name ] = {
                  get: function( elem, computed, extra ) {
                      if ( computed ) {
                          return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
                              jQuery.swap( elem, cssShow, function() {
                                  return getWidthOrHeight( elem, name, extra );
                              }) :
                              getWidthOrHeight( elem, name, extra );
                      }
                  },
      
                  set: function( elem, value, extra ) {
                      var styles = extra && getStyles( elem );
                      return setPositiveNumber( elem, value, extra ?
                          augmentWidthOrHeight(
                              elem,
                              name,
                              extra,
                              jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
                              styles
                          ) : 0
                      );
                  }
              };

      get 方法:

      1 节点隐藏等情况下,height、width等获取值不准,此时需利用jQuery.swap方法来获得准确值

      2 getWidthOrHeight获取准确值

       

      本章大体回顾下了跟HTML相关处理的10种方法与jQuery中相对应的处理流,下章再具体分析jQuery中对应每种不同兼容的处理

     

  • 相关阅读:
    理解MySQL——索引与优化
    一个简单的效果可以拖动的div
    jsp中验证码的实现
    java经典算法四十题
    java.util.Date和java.sql.Date的区别及应用
    懒人笔记memcache配置(php)
    很奇怪的SQL问题,top和inner join一起使用时出现排序问题
    aspnet_regiis一些技巧
    webservice服务输出xml格式自定义格式内容
    FCK配置中文版(转自网络,未知来源)
  • 原文地址:https://www.cnblogs.com/aaronjs/p/3565253.html
Copyright © 2020-2023  润新知