摘要:而且它還是只讀的屬性,所以通過來改變樣式,如果不能修改文件的情況下,只能采用內聯。一般的思路就是,先看看有沒有內聯,如果沒有內聯,就走一般流程。
歡迎來我的專欄查看系列文章。
樣式操作也是 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 新建一個 標簽,很顯然,第一種貌似更符合 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。
歡迎來我的博客交流。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/86828.html
摘要:需要把的元信息從中解析出來,做一些檢查,然后把的元信息持久化保存到中。主要做件事修改的元信息,把加入到的元信息中去。從隊列中取出,根據的類型調用函數。的狀態變為之后,會調用將的元信息從上刪除。 DDL 是數據庫非常核心的組件,其正確性和穩定性是整個 SQL 引擎的基石,在分布式數據庫中,如何在保證數據一致性的前提下實現無鎖的 DDL 操作是一件有挑戰的事情。本文首先會介紹 TiDB D...
摘要:一團隊組織網站說明騰訊團隊騰訊前端團隊,代表作品,致力于前端技術的研究騰訊社交用戶體驗設計,簡稱,騰訊設計團隊網站騰訊用戶研究與體驗設計部百度前端研發部出品淘寶前端團隊用技術為體驗提供無限可能凹凸實驗室京東用戶體驗設計部出品奇舞團奇虎旗下前 一、團隊組織 網站 說明 騰訊 AlloyTeam 團隊 騰訊Web前端團隊,代表作品WebQQ,致力于前端技術的研究 ISUX 騰...
摘要:一團隊組織網站說明騰訊團隊騰訊前端團隊,代表作品,致力于前端技術的研究騰訊社交用戶體驗設計,簡稱,騰訊設計團隊網站騰訊用戶研究與體驗設計部百度前端研發部出品淘寶前端團隊用技術為體驗提供無限可能凹凸實驗室京東用戶體驗設計部出品奇舞團奇虎旗下前 一、團隊組織 網站 說明 騰訊 AlloyTeam 團隊 騰訊Web前端團隊,代表作品WebQQ,致力于前端技術的研究 ISUX 騰...
閱讀 1196·2021-10-11 10:59
閱讀 1977·2021-09-29 09:44
閱讀 864·2021-09-01 10:32
閱讀 1438·2019-08-30 14:21
閱讀 1881·2019-08-29 15:39
閱讀 2987·2019-08-29 13:45
閱讀 3544·2019-08-29 13:27
閱讀 2016·2019-08-29 12:27