博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
jQuery-1.9.1源码分析系列(七) 钩子(hooks)机制及浏览器兼容续
阅读量:6838 次
发布时间:2019-06-26

本文共 9958 字,大约阅读时间需要 33 分钟。

  前面一章分析了jQuery.support、钩子原理和属性钩子。这一章主要分析CSS钩子。

 

b. css操作的钩子


  CSS钩子种类:

  cssHooks

  cssNumber

  cssProps

 

jQuery.cssHooks的对象

  不过cssHooks中的set函数的作用有些不同,set函数并没有真正的设置相应的值,而是修正要设置到CSS中的值。获取到修正值以后,设置在jQuery.style函数中进行。后面分析几个CSS钩子

  获取opacity返回的值需要时数字

cssHooks: {  opacity: {    get: function( elem, computed ) {      if ( computed ) {        //需要返回数字                              var ret = curCSS( elem, "opacity" );        return ret === "" ? "1" : ret;      }    }  }},
View Code

  当设置display为none等的时候是不能获取到宽高的,所以需要将元素设为display为block,visibility设置为hidden来获取宽高;设置宽高需要根据CSS样式boxSizing的取值来确定。

jQuery.each([ "height", "width" ], function( i, name ) {  jQuery.cssHooks[ name ] = {    get: function( elem, computed, extra ) {      if ( computed ) {               //当设置display为none等的时候是不能获取到宽高的,                //所以需要将元素设为display为block,               //visibility设置为hidden来获取宽高               // rdisplayswap = /^(none|table(?!-c[ea]).+)/,               //cssShow ={ position: "absolute", visibility: "hidden", display: "block" }                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      );    }  };});
View Code

 

  IE使用filters来设置不透明度;IE要设置不透明度更加复杂,需保证有布局,如果设置不透明度为1,并且没有别的filters存在,尝试移除filter属性等

if ( !jQuery.support.opacity ) {  jQuery.cssHooks.opacity = {    get: function( elem, computed ) {      // IE使用filters来设置不透明度,ropacity = /opacity\s*=\s*([^)]*)/      return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?      ( 0.01 * parseFloat( RegExp.$1 ) ) + "" :      computed ? "1" : "";    },    set: function( elem, value ) {      var style = elem.style,      currentStyle = elem.currentStyle,      opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",      filter = currentStyle && currentStyle.filter || style.filter || "";       //IE7中滤镜(filter)必须获得布局才能生效,我们用zoom这个IE私有属性让其获得布局      style.zoom = 1;       //ie处理,如果设置不透明度为1,并且没有别的filters存在,尝试移除filter属性      //如果只为“”,删除内联的opacity,ralpha = /alpha\([^)]*\)/i      if ( ( value >= 1 || value === "" ) && jQuery.trim( filter.replace( ralpha, "" ) ) === "" && style.removeAttribute ) {        //设置style.filter为null, "" 或 " ",结果是"filter:"依然在cssText中        //如果当下"filter:"存在则清除类型不可用,我们应当避免        // style.removeAttribute是IE独有        style.removeAttribute( "filter" );         //如果当前没有filter样式应用于css rule或未设置内联的不透明则返回        if ( value === "" || currentStyle && !currentStyle.filter ) {          return;        }      }       // 其他情况设置filter values      style.filter = ralpha.test( filter ) ?      filter.replace( ralpha, opacity ) :      filter + " " + opacity;    }  };}
View Code

  webkit的bug:getComputedStyle返回margin-right值错误;当指定为top/left/bottom/right时,使用getComputedStyle 返回百分比结果,使用jQuery( elem ).position()来获取。

//DOM加载完成后才能做support测试,在添加下面的HooksjQuery(function() {    if ( !jQuery.support.reliableMarginRight ) {           jQuery.cssHooks.marginRight = {               get: function( elem, computed ) {                   if ( computed ) {                       // WebKit Bug 13343 - getComputedStyle返回margin-right值错误                       //设置元素的display为inline-block来解决                       return jQuery.swap( elem, { "display": "inline-block" },                               curCSS, [ elem, "marginRight" ] );                   }               }           };    }     // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084    // getComputedStyle 返回百分比当指定为top/left/bottom/right    //我们使用jQuery( elem ).position()来获取    if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {           jQuery.each( [ "top", "left" ], function( i, prop ) {               jQuery.cssHooks[ prop ] = {                    get: function( elem, computed ) {                       if ( computed ) {                               computed = curCSS( elem, prop );                               // if curCSS returns percentage, fallback to offset                               //rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),                               return rnumnonpx.test( computed ) ?                               jQuery( elem ).position()[ prop ] + "px" :                               computed;                       }                   }               };           });    }});
View Code

  后面这个钩子与众不同,他使用在动画的展开上。我们知道margin/padding/borderWidth实际上不是一个CSS属性,而是四个CSS属性的集合。所以三个CSS的expand钩子实际上是将他们拆分成四个属性给提取出来。

  // 这里的hooks用在动画的展开特征上  jQuery.each({        margin: "",        padding: "",        border: "Width"        }, function( prefix, suffix ) {            jQuery.cssHooks[ prefix + suffix ] = {                expand: function( value ) {                    var i = 0,                    expanded = {},                        //如果不是字符串则假设为一个单独的数字                        parts = typeof value === "string" ? value.split(" ") : [ value ];                        for ( ; i < 4; i++ ) {                            //cssExpand = [ "Top", "Right", "Bottom", "Left" ],                            expanded[ prefix + cssExpand[ i ] + suffix ] =                            parts[ i ] || parts[ i - 2 ] || parts[ 0 ];                        }                        return expanded;                    }            };            if ( !rmargin.test( prefix ) ) {            jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;        }    });
View Code

 

jQuery. cssNumber和jQuery.cssProps的对象

//下面的css特征值后面不能添加“px”字段cssNumber: {    "columnCount": true,    "fillOpacity": true,    "fontWeight": true,    "lineHeight": true,    "opacity": true,    "orphans": true,    "widows": true,    "zIndex": true,    "zoom": true}, //float对应的css特征名需要在使用前修正cssProps: {    // normalize float css property    "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"},

  拓展:

  有一些CSS属性需要在某些特定条件下才能获取正确。这种情况需要模拟场景获取值,然后恢复先前的场景。swap就是用来专门模拟场景,获取值以后恢复场景的函数。

// 一种快速切换输入/输出css特征值(计算前保存css特征,计算中更改css特征以获取计算结果,计算结束后恢复先前保存的css特征)以获取正确计算结果的方法swap: function( elem, options, callback, args ) {    var ret, name,        old = {};     // 保存原来的特征值,设置为保证计算成功而修改的特征(property)值    for ( name in options ) {           old[ name ] = elem.style[ name ];           elem.style[ name ] = options[ name ];    }    //调用回调计算结果    ret = callback.apply( elem, args || [] );     // 恢复原来的特征值    for ( name in options ) {           elem.style[ name ] = old[ name ];    }    //返回计算结果    return ret;}

  setPositiveNumber函数对要设置给CSS属性的值做修正,比如添加"px"结尾等

// rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),//用来匹配数字,.source返回表达式字符串自身//core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,//返回指定value和subtract对应应该设置的css样式值function setPositiveNumber( elem, value, subtract ) {    var matches = rnumsplit.exec( value );    return matches ?    // 注意没有定义的"subtract",例如在cssHooks中使用时    Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :    value;}

  getWidthOrHeight函数提供获取CSS宽高属性的计算方法

//获取宽度或高度function getWidthOrHeight( elem, name, extra ) {    //首先获取offset特征值,相当于包括边框在内的盒宽高    var valueIsBorderBox = true,        val = name === "width" ? elem.offsetWidth : elem.offsetHeight,        styles = getStyles( elem ),        isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";    //一些非html元素offsetWidth返回undefined,因此检查null/undefined    if ( val <= 0 || val == null ) {        //如果计算失败则在必要的情况下使用未计算的结果        val = curCSS( elem, name, styles );        if ( val < 0 || val == null ) {            val = elem.style[ name ];        }        //已计算的单元为非像素单位则终止并返回        if ( rnumnonpx.test(val) ) {            return val;        }        //我们需要检查style,避免浏览器使用getComputedStyle返回不可靠的值而悄悄的回到可靠的elem.style值        valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );        //规范“”,auto为拓展做准备        val = parseFloat( val ) || 0;    }    //使用动态box-sizing模型来添加/减少不相干的样式    return ( val +        augmentWidthOrHeight(            elem,            name,            extra || ( isBorderBox ? "border" : "content" ),            valueIsBorderBox,            styles            )        ) + "px";}//extra表示计算时要包括的部分function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {    //在循环中遍历cssExpand时使用    //其中cssExpand = [ "Top", "Right", "Bottom", "Left" ],    var i = extra === ( isBorderBox ? "border" : "content" ) ?        //如果我们有了正确的测量结果,避免增大,正常情况下会走这一步        4 :        //否则初始化为水平或垂直特征(property)        name === "width" ? 1 : 0,    val = 0;    for ( ; i < 4; i += 2 ) {        //两种盒模型都排除margin,如果计算要包括margin,则加上他        if ( extra === "margin" ) {            val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );        }        //如果是border-box模型        if ( isBorderBox ) {            // border-box包括padding,如果我们需要内容部分因此要减去他            if ( extra === "content" ) {                val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );            }            //此时,extra不是边框也非margin时,减去边框            if ( extra !== "margin" ) {                val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );            }        //如果是content-box模型        } else {            //此时,extra不是内容,所以加上padding            val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );            //此时,extra不是内容也不是padding,所以加上边框            if ( extra !== "padding" ) {                val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );            }        }    }    return val;}

 

   如果觉得本文不错,请点击右下方【推荐】!

转载地址:http://wfqkl.baihongyu.com/

你可能感兴趣的文章
走进JavaWeb技术世界7:Tomcat中的设计模式
查看>>
阅读mutate源码学习dplyr
查看>>
layui upload 额外参数上传
查看>>
我来悟微服务(3)-需求管理
查看>>
fatal error LNK1112: module machine type 'x64' conflicts with target machine type 'X86'
查看>>
SpringBoot-14-MyBatis预热篇,MySQL小结
查看>>
深度学习基础与技巧
查看>>
Firefox 将导入 Windows 根证书,避免与杀毒软件的冲突
查看>>
Windows搭建golang开发平台
查看>>
多线程基础篇(3)——初试锁
查看>>
利用WSS搭建学生作业平台
查看>>
刚进入win7系统就提示检测到一个硬盘问题的解决方法
查看>>
Python之配置日志模块logging
查看>>
指定目录的所有 *.gif 文件都重命名为 *.jpg
查看>>
为11.2.0.2 Grid Infrastructure添加节点
查看>>
Linux运维课程 第一阶段 重难点摘要(六)CISCO
查看>>
inotify结合rsync监控目录的实时变化
查看>>
pfSense book之硬件配置指南
查看>>
存储过程总结 2
查看>>
js parsefloat
查看>>