欢迎来我的专栏检察系列文章。
款式操纵也是 jQuery 比较经常运用的一个操纵,就我本人而言,这个 css 函数用多了,觉得本身有点傻乎乎的,重要照样本身不相识 js 中 css 的真正寄义。
不过如今不怕了。
最先之前,先抛开 jQuery,我们来看看一个风趣的面试题(据说是一道微信面试题)。
一道很有深度的面试题
用原生的 js 取得一个 HTML 元素的 background-color
,固然,这只是一个引入,为何不是 color,为何不是 font-size?
css 衬着的优先级
写过 css 款式的同砚都晓得,css 是有优先级辨别的,!important
优先级最高,内联优先级其次,id,类和伪类,元素和伪元素。优先级会根据递次顺次比较,一致级别雷同则看下一级别,优先级雷同,背面会掩盖前面。
比方,就像理科生排结果,划定 总分 > 数学 > 语文 > 英语
,假如 A,B 两人总分一样,就看数学结果谁高,数学结果一样,就看语文结果谁高,以此类推。
记得在一家公司练习的时刻(初学者),谁人时刻修正网站的主页款式,由于找不到款式对应,就大批运用 !important
,并把一切款式都写在款式标的末了,预计,背面接办的人要气炸吧。
问题来了,关于恣意的一个 elem,DIV 也好,P 也好,都只会保存一个 style 款式表,平常能够经由过程 getComputedStyle
函数或 IE 的 currentStyle 参数运动(万恶的 IE,如今 jQuery 已不支撑低版本 IE,连淘宝都不支撑 IE8 了)。不管这个款式表是经由过程前面哪一个优先级取得的,但它一定是唯一且只要一个。而且它照样只读的属性,所以经由过程 JS 来转变款式,假如不能修正 css 文件的情况下,只能采纳内联。
内联有两种,一种是在 elem 上增加一个 style 属性,另有一种是在 HTMl 新建一个 <style>
标签,很显然,第一种貌似更相符 js 的特征,由于找到谁人 elem 并不难题,而且另有一个 elem.style
能够运用。
js 猎取元素款式
elem.style
并非全能的,也有很大的局限性。平常的思绪就是,先看看有没有内联,假如没有内联,就走平常流程。
内联值和 getComputedStyle 的值会不一样吗,我本身做过测试,在 chrome 下面,内联值和款式表 getComputedStyle 的值是一样的,而且,当内联值转变,款式表也会随着转变,除非在 css 文件中有比内联优先级还高的 important,这个时刻内联是不起作用的,只能经由过程款式表来猎取。
var dom = document.getElementById("test");
var styleList = getComputedStyle(dom);
styleList.color; // 'black'
dom.style.color = 'red';
// 会自动革新的
styleList.color; // 'red'
当 styleList.color
稳定的时刻,就晓得可能有 important 款式的存在,也能够作为推断 important 的一个规范。
款式表有 font-size
,有人写成驼峰 fontSize
,这能够明白,一致一下就好啦。由于 elem.style
和 getComputedStyle
运用的是驼峰写法(实际上即运用破折法去猎取也是能够获得的)要借助下面这两个函数来:
// 变成驼峰
function camel(str){
return str.replace(/-(\w)/g, function(m0, m1){
return m1.toUpperCase();
})
}
// 变成破折
function dashes(str){
return str.replace(/[A-Z]/g, function(m0){
return '-' + m0.toLowerCase();
})
}
因而:
function getStyle(elem, name){
var value, styles, sty;
if(!name){ // 只要一个参数,直接返回吧
return false;
}
if(elem.nodeType !==1 && elem.nodeType !== 9 && elem.nodeType !== 11){
// 一定不是 HTMLElement
return false;
}
name = camel(name); //将 name 转变成驼峰
value = elem.style[name];
if(value){
return value;
}
styles = (sty = elem.currentStyle) ? sty :
(sty = document.defaultView.getComputedStyle) ? sty(elem) : {};
return (sty = styles[name]) ? sty : false;
}
// 测试,疏忽驼峰和破折
getStyle(dom, 'font-size'); // '16px'
getStyle(dom, 'fontSize'); // '16px'
这道问题照样很有意义的,固然,答案还不止,还能够继续优化,如许能够给面试官好感,链接。
由于我们测的是 background-color,这个属性很迥殊,当它是 inherit
示意继续父类,transparent
示意通明,也该为 flase,看:
function fixColor(elem){
var color = getStyle(elem, 'background-color');
if(color){
if(color == 'transparent' || color == 'rgba(0, 0, 0, 0)')
return false;
else if(getStyle(elem, 'opacity') == '0'){
return false; // 通明
}
else if(getStyle(elem, 'display') == 'none'){
return false; // none
}
else if(getStyle(elem, 'visibility') == 'hidden'){
return false; // 隐蔽
}
}
if(color == 'inherit'){ // 继续父
return elem.parentNode ? fixColor(elem.parentNode) : false;
}
return color;
}
愈来愈有意义了。假如是 html5 中的 canvas,貌似又要去找。
fn.css() 源码
好吧,步入正题了。我想,假如细致看了前面面试题的同砚,也该对原生 js 操纵 css 做法完整懂了,jQuery 的思绪也完整是云云,只是多了更多的兼容斟酌:
jQuery.fn.extend( {
css: function( name, value ) {
return access( this, function( elem, name, value ) {
var styles, len,
map = {},
i = 0;
if ( jQuery.isArray( name ) ) {
styles = getStyles( elem );
len = name.length;
for ( ; i < len; i++ ) {
map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
}
return map;
}
return value !== undefined ?
jQuery.style( elem, name, value ) :
jQuery.css( elem, name );
}, name, value, arguments.length > 1 );
}
} );
css 也是有 set 和 get 的,然则它们并不在 fn.css
函数里处置惩罚,set 对应 jQuery.style
,get 对应 jQuery.css
。
在此之前,先来看一个很熟悉的函数:
var getStyles = function( elem ) {
// Support: IE <=11 only, Firefox <=30 (#15098, #14150)
// IE throws on elements created in popups
// FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
var view = elem.ownerDocument.defaultView;
if ( !view || !view.opener ) {
view = window;
}
return view.getComputedStyle( elem );
};
jQuery 已不支撑 currentStyle,也就是扬弃了低版本 IE 浏览器。
jQuery.extend( {
camelCase: function( string ) {
return string.replace( /^-ms-/, "ms-" ).replace( /-([a-z])/g, function( all, letter ) {
return letter.toUpperCase();
} );
}
} );
camelCase 也是一个很熟悉的函数(ms 是有其他用处的)。
jQuery.extend( {
style: function( elem, name, value, extra ) {
// 处置惩罚特殊情况 !elem.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, hooks,
origName = jQuery.camelCase( name ),
style = elem.style;
name = jQuery.cssProps[ origName ] ||
( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName );
// hooks
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
// Check if we're setting a value
if ( value !== undefined ) {
type = typeof value;
// Convert "+=" or "-=" to relative numbers (#7345)
if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {
value = adjustCSS( elem, name, ret );
// Fixes bug #9237
type = "number";
}
// Make sure that null and NaN values aren't set (#7116)
if ( value == null || value !== value ) {
return;
}
// If a number was passed in, add the unit (except for certain CSS properties)
if ( type === "number" ) {
value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" );
}
// background-* props affect original clone's values
if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
style[ name ] = "inherit";
}
// If a hook was provided, use that value, otherwise just set the specified value
if ( !hooks || !( "set" in hooks ) ||
( value = hooks.set( elem, value, extra ) ) !== undefined ) {
style[ name ] = value;
}
} else {
// If a hook was provided get the non-computed value from there
if ( hooks && "get" in hooks &&
( ret = hooks.get( elem, false, extra ) ) !== undefined ) {
return ret;
}
// 历尽艰辛,终究比及你
return style[ name ];
}
}
} );
jQuery.extend( {
css: function( elem, name, extra, styles ) {
var val, num, hooks,
origName = jQuery.camelCase( name );
// Make sure that we're working with the right name
name = jQuery.cssProps[ origName ] ||
( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName );
// Try prefixed name followed by the unprefixed name
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
// If a hook was provided get the computed value from there
if ( hooks && "get" in hooks ) {
val = hooks.get( elem, true, extra );
}
// Otherwise, if a way to get the computed value exists, use that
if ( val === undefined ) {
val = curCSS( elem, name, styles );
}
// Convert "normal" to computed value
if ( val === "normal" && name in cssNormalTransform ) {
val = cssNormalTransform[ name ];
}
// Make numeric if forced or a qualifier was provided and val looks numeric
if ( extra === "" || extra ) {
num = parseFloat( val );
return extra === true || isFinite( num ) ? num || 0 : val;
}
return val;
}
} );
总结
假如你对 css 看起来很费劲,请把谁人微信面试题再细致阅读一下吧。
参考
解密jQuery内核 款式操纵
CSS并不简朴–一道微信面试题的实践
微信面试题-猎取元素的终究background-color
本文在 github 上的源码地点,欢迎来 star。
欢迎来我的博客交换。