您的位置:首页 > Web前端 > JQuery

jQuery-1.9.1源码分析系列(七) 钩子(hooks)机制及浏览器兼容续

2015-11-16 16:29 633 查看
  前面一章分析了jQuery.support、钩子原理和属性钩子。这一章主要分析CSS钩子。

b. css操作的钩子

  CSS钩子种类:

  cssHooks

  cssNumber

  cssProps

jQuery.cssHooks的对象

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

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

  // 这里的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;
}


  如果觉得本文不错,请点击右下方【推荐】!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: