为了账号安全,请及时绑定邮箱和手机立即绑定

jQuery乱谈

标签:
JQuery

今天主要分析jQuery处理元素CSS相关属性的内部实现。相关方法:addClass()、hasClass()、removeClass()、toggleClass()、css()、jQuery.cssHooks、height()、width()、innerHeight()、innerWidth()、outerHeight()、outerWidth()、offset()、position()、scrollLeft()、scrollTop()。其中addClass()、hasClass()、removeClass()、toggleClass()在前面的jQuery乱谈(五)、jQuery乱谈(六)已经分析过,这里不再唠叨。

  css():

css: function( name, value ) {         return jQuery.access( this, function( elem, name, value ) {             return value !== undefined ?                 jQuery.style( elem, name, value ) :                 jQuery.css( elem, name );         }, name, value, arguments.length > 1 );     }

       

  该方法可以接受两个参数,第二个参数是可选的。当该方法只接收一个参数时,该参数有两个意义,若只是一个css属性名字符串,方法可以返回匹配元素集合中的第一个元素的参数样式属性值;若该参数是一个CSS属性-值对象,则对所有的匹配元素设置相应的CSS属性。当接收两个参数时,为匹配的所有元素设置相应的CSS属性。

.css( propertyName ) 
 

为匹配的元素集合中获取第一个元素的样式属性值。

  • .css( propertyName )

    propertyName         一个css属性名

.css( propertyName, value ) 
 

为匹配的元素设置一个或多个CSS属性。

  • .css( propertyName, value )

    propertyName                             一个CSS属性名

    value                                          一个CSS属性名的值

  • .css( propertyName, function(index, value) )

    propertyName                            一个CSS属性名

    function(index, value)                一个返回设置值的函数。接收元素的索引位置和元素旧的样式属性值作为参数。

  • .css( map )

    map                                         CSS属性值( property-value)对象映射.

 

  CSS()方法在内部实现上使用了jQuery.access()方法,这个全局内部方法主要用于.css()、.attr()、.prop()。你可以把它想象成一个集装箱,我们只要把参数交给他就可以了,具体的实现不用我们关注。这里我们主要关注:

function( elem, name, value ) {             return value !== undefined ?                 jQuery.style( elem, name, value ) :                 jQuery.css( elem, name );         }

   

  该参数会自行判断.css()方法提供了几个参数,然后分别执行对应的方法:jQuery.style()、jQuery.css()。

  jQuery.style()主要负责在DOM节点上读取或设置样式属性,该方法主要作用如下:过滤Text和Comment节点,过滤掉无style的元素,返回undefined;属性名转换为驼峰式;设置或读取样式。源码分析如下:

// 在DOM节点上读取或设置样式属性 style: function( elem, name, value, extra ) {     // 过滤Text和Comment,如果没有style属性也直接返回     if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {         return;     }      // Make sure that we're working with the right name     // 确保使用了正确的名字     var ret, type, origName = jQuery.camelCase( name ),         style = elem.style, hooks = jQuery.cssHooks[ origName ]; // 转换为驼峰格式     // 修正属性名,是否在不同的浏览器中使用不同的属性名     name = jQuery.cssProps[ origName ] || origName; // CSS钩子      // Check if we're setting a value     // 设置     if ( value !== undefined ) {         type = typeof value;          // 计算相对值 rrelNum = /^([\-+])=([\-+.\de]+)/, //         if ( type === "string" && (ret = rrelNum.exec( value )) ) {             /*              * ret[1] 正负;ret[2] 相对值              * +( ret[1] + 1) ret[1]是字符串,加上1变成'+1'或'-1',最前边的加号将字符串转换为数字1或-1              * +ret[2] 同样的加号将ret[2]转换为数字              * 正负1 乘以 相对值 再加上 当前值,得出要设置的值              */             // #9237:.css()在带有连字符的属性上不能工作,在1.6.2中修正             type = "number";         }          // 过滤NaN null,不做任何处理,如果想从内联样式中删除某个属性,请传入空字符串         if ( value == null || type === "number" && isNaN( value ) ) {             return;         }          // 如果传入一个数字,追加单位px(jQuery.cssNumber中定义的属性除外,见jQuery.cssNumber的定义)         if ( type === "number" && !jQuery.cssNumber[ origName ] ) {             value += "px";         }          // 前边的都是前戏:过滤非法参数、计算相对值、追加单位后缀          /*          * 如果有钩子hooks,且hooks中存在set函数,则调用hooks.set,将返回值赋给value          * 如果hooks.set的返回值为undefined,则不执行任何操作;返回值不为undefined,则用新value设置样式值          * 简单点说,有hooks.set则调用,用返回值替换value,最后设置style.name;否则直接设置style.name          * 可见钩子的作用是修正属性值,并不直接对值进行设置          * 等价的逻辑:          * <pre>          * if ( hooks && "set" in hooks ) {          *   value = hooks.set( elem, value );          *   if( value != undefined ) style[ name ] = value;          * } else {            *   style[ name ] = value;          * }          * </pre>          */         if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {              // 用try-catch块,预防在IE中,当用不合法的值设置样式值时,抛出异常             try {                 style[ name ] = value;             } catch(e) {}         }     // 读取     } else {         // 如果有钩子hooks,则调用hooks.get,返回值赋给ret         if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {             return ret;         }          // 否则从style对象中读取属性值         return style[ name ];     } }

       

  读取和设置样式表遇到的难题是浏览器兼容性。例如访问样式属性时的方式就不同:

// W3C var defaultView = elem && elem.ownerDocument.defaultView; var computedStyle = defaultView && defaultView.getComputedStyle( elem, null ); var ret = computedStyle && computedStyle.getPropertyValue( name ); return ret; // IE var ret = elem.currentStyle && elem.currentStyle[ name ] return ret;

       

  另一个常见的兼容问题是,某些属性在不同的浏览器中使用不同的属性名,例如float,在IE的DOM实现中用styleFloat,而在遵守W3C标准的浏览器中是 cssFloat。另外,多个单词组成的样式属性在CSS和DOM有着不一样的格式,jquery通过方法jQuery.camelCase()将连词符格式转为驼峰格式。

  

  接着是jQuery.css() ,该方法负责读取样式值。它主要完成如下任务:属性名转换为驼峰式;如果有钩子,则调用钩子的get;否则调用curCSS,不同的浏览器调用不同的方法:

    IE:getComputedStyle,elem.ownerDocument.defaultView.getComputedStyle( elem, null ).getPropertyValue( name )

    W3C:currentStyle,elem.currentStyle[ name ]

  源码分析如下:

// 读取样式值 css: function( elem, name, extra ) {     var ret, hooks;      name = jQuery.camelCase( name ); // 转换为驼峰式     hooks = jQuery.cssHooks[ name ]; // 是否有钩子     name = jQuery.cssProps[ name ] || name; // 修正属性名      // cssFloat需要特殊处理,(styleFloat不需要吗?)     if ( name === "cssFloat" ) {         name = "float"; // 又把它转换回去了!     }      // 如果钩子hooks存在,则调用hooks.get计算样式值,并返回     if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {         return ret;           // 否则,如果curCSS存在,则调用curCSS获取计算后的样式值,并返回     } else if ( curCSS ) {         return curCSS( elem, name );     } }

       

  里面又涉及到了curCSS( elem, name ),该方法主要将getComputedStyle或currentStyle统一,代码分析如下:

// W3C
if ( document.defaultView && document.defaultView.getComputedStyle ) {     getComputedStyle = function( elem, name ) {         var ret, defaultView, computedStyle; // 预定义变量         // 将驼峰式转换为连字符,例如marginTop > margin-top         // rupper = /([A-Z]|^ms)/g,         name = name.replace( rupper, "-$1" ).toLowerCase();          /*          * 分解:          * var defaultView = elem && elem.ownerDocument.defaultView;          * var computedStyle = defaultView && defaultView.getComputedStyle( elem, null );          * var ret = computedStyle && computedStyle.getPropertyValue( name );          * return ret;          */         if ( (defaultView = elem.ownerDocument.defaultView) &&                 (computedStyle = defaultView.getComputedStyle( elem, null )) ) {             ret = computedStyle.getPropertyValue( name );              if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {                 ret = jQuery.style( elem, name );             }         }          return ret;     }; }
   // IE if ( document.documentElement.currentStyle ) {     currentStyle = function( elem, name ) {         var left, rsLeft, uncomputed,             ret = elem.currentStyle && elem.currentStyle[ name ], // 直接就取值             style = elem.style;           /*          * 避免返回空字符串          * 如果elem.currentStyle[ name ]返回null,用style[name]试试          */         if ( ret === null && style && (uncomputed = style[ name ]) ) {             ret = uncomputed;         }          /*          * 不处理一般的像素值,但是如果单位很奇怪就需要修正为像素px          * rnumpx = /^-?\d+(?:px)?$/i, // 可选的负号 加 数字 加 可选的px,对数值进行检查          * rnum = /^-?\d/, // 整数,不支持+1这样的写法(应该支持)          *           * 数字后跟了非像素单位          *           *           */         if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {              // Remember the original values             // 记录原始值             left = style.left;             rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;                if ( rsLeft ) {                  elem.runtimeStyle.left = elem.currentStyle.left;             }             style.left = name === "fontSize" ? "1em" : ( ret || 0 );             ret = style.pixelLeft + "px";              // Revert the changed values             style.left = left;             if ( rsLeft ) {                 elem.runtimeStyle.left = rsLeft;             }         }          return ret === "" ? "auto" : ret;     }; }  curCSS = getComputedStyle || currentStyle;

       

  jQuery.cssHooks主要用于修正CSS样式属性在浏览器中的差异。例如:opacity等。代码很简单,就不分析了:

cssHooks: {         opacity: {             get: function( elem, computed ) {                 if ( computed ) {                     // We should always get a number back from opacity                     var ret = curCSS( elem, "opacity" );                     return ret === "" ? "1" : ret;                  }             }         }     }

       

  已经写的够多了,下一篇再分析height()、width()、innerHeight()、innerWidth()、outerHeight()、outerWidth()、offset()、position()、scrollLeft()、scrollTop()。

   

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消