基礎總結css
一個元素的樣式信息由三個來源根據層疊規則肯定。三個來源分別是:node
元素的樣式web
任何支持style特性的HTML元素在JavaScript中都有一個對應的style屬性。這個style對象是CSSStyleDeclaration的實例,包含着經過HTML的style特性指定的全部樣式信息,但不包含與外部樣式表或嵌入樣式表經層疊而來的樣式。在style特性中指定的任何css屬性均可以經過這個style對象相應的屬性來訪問(對於短劃線的css屬性必須轉化成駝峯形式:background-color=》backgroundColor)。除「float」外大部分css屬性均可以經過簡單轉化爲屬性形式訪問,由於float來JavaScript中屬於保留字,因此在firefox、chrome、opera、safari等瀏覽器中對應JavaScript屬性爲cssFloat,而在Ie中對應爲styleFLoat。正則表達式
「DOM2級樣式」規範中爲CSSStyleDeclaration對象定義了一系列的屬性和方法(IE9+):chrome
元素的樣式api
"DOM2級樣式"加強了document.defaultView,defaultView指向當前文檔所在的window對象。該對象增長了一個getComputedStyle(node, pseudo)方法,該方法返回一個CSSStyleDeclaration對象,包含當前元素的全部計算樣式。而IE中並不支持該方法,與其對應的是node.style.currentStyle屬性,該屬性也是CSSStyleDeclaration的實例,包含當前元素全部計算後的樣式。不管在哪一個瀏覽器中,全部計算後的樣式都是隻讀的。瀏覽器
樣式表
app
CSSStyleSheet類型表明樣式表,僅僅是樣式表,不管是經過<link>元素包含的樣式表和在<style>元素中定義的樣式表。CSSStyleSheet對象是一套只讀的接口(除了disabled屬性)。CSSStyleSheet接口的屬性以下:dom
也能夠直接經過<link>或<style>元素取得CSSStyleSheet對象。element.sheet指向表明該元素樣式表的CSSStyleSheet對象。IE中不支持該屬性,但支持一個styleSheet屬性。ide
CSS規則
CSSRule對象表示樣式表中的一條規則。CSSStyleRule繼承自CSSRule類,並提供瞭如下屬性:
其中cssText、selectorText、style三個屬性最經常使用,cssText與style.cssText屬性相似,但cssText包含選擇符文本和圍繞樣式信息的花括號,而style.cssText只有樣式信息,style.cssText是可讀寫的而cssText是隻讀的。
這幾種類型的關係以下圖所示:
dojo/dom-style
該模塊提供兩個方法:get和set。
對於取值,最重要的是獲取樣式層疊以後的計算值,因此要使用的原生api就是getComputedStyle。可是該函數有兼容性問題,上文提到過IE中沒有該方法,只能經過element.currentStyle來達到相同的效果;另外,webkit內核瀏覽器中若是node的display爲none,這時調用getComputedStyle是沒法取到正確結果的,這裏dojo本身處理了一下將其diaplay設爲空字符串。一下即是dojo中對getComputedStyle的處理:
var getComputedStyle, style = { // summary: // This module defines the core dojo DOM style API. }; // nodeType爲1,表明元素節點 if(has("webkit")){ getComputedStyle = function(/*DomNode*/ node){ var s; if(node.nodeType == 1){ var dv = node.ownerDocument.defaultView; s = dv.getComputedStyle(node, null); // node不可見時,沒法獲得有效結果 if(!s && node.style){ node.style.display = ""; s = dv.getComputedStyle(node, null); } } return s || {}; }; }else if(has("ie") && (has("ie") < 9 || has("quirks"))){ getComputedStyle = function(node){ return node.nodeType == 1 && node.currentStyle ? node.currentStyle : {}; }; }else{ getComputedStyle = function(node){ return node.nodeType == 1 ? node.ownerDocument.defaultView.getComputedStyle(node, null) : {}; }; } style.getComputedStyle = getComputedStyle;
到這裏咱們僅僅能獲得計算後的樣式值,但getComputedStyle方法的樣式值是帶有單位的,而實際應用中咱們每每須要的是數字值。因此接下來的步驟就是將計算值轉化成數字:
var toPixel; if(!has("ie")){ toPixel = function(element, value){ //非ie瀏覽器直接轉化成數字 return parseFloat(value) || 0; }; }else{ // ie瀏覽器下則要進行各類兼容處理 toPixel = function(element, avalue){ if(!avalue){ return 0; } // 對於border-width 可能設置爲medium,這時咱們認爲寬度爲4 if(avalue == "medium"){ return 4; } // 帶px單位的,去掉px便可;slice函數參數爲負數的至關於length+負數 if(avalue.slice && avalue.slice(-2) == 'px'){ return parseFloat(avalue); } // 下面這段沒看懂。。。。。 var s = element.style, rs = element.runtimeStyle, cs = element.currentStyle, sLeft = s.left, rsLeft = rs.left; rs.left = cs.left; try{ // 'avalue' may be incompatible with style.left, which can cause IE to throw // this has been observed for border widths using "thin", "medium", "thick" constants // those particular constants could be trapped by a lookup // but perhaps there are more s.left = avalue; avalue = s.pixelLeft; }catch(e){ avalue = 0; } s.left = sLeft; rs.left = rsLeft; return avalue; }; } style.toPixelValue = toPixel;
處理完這些以後,讓咱們先看一下dojo/dom-style.get方法:
style.get = function getStyle(/*DOMNode|String*/ node, /*String?*/ name){ var n = dom.byId(node), l = arguments.length, op = (name == "opacity"); // 對於opacity作兼容處理,非ie直接使用css中的opacity屬性; ie8如下瀏覽器並不支持,這時就須要使用濾鏡,因此取值時候也要特殊處理 if(l == 2 && op){ return _getOpacity(n); } // 對於float保留字的處理,非ie用的是CSSFloat而ie使用的是styleFloat name = _floatAliases[name] ? "cssFloat" in n.style ? "cssFloat" : "styleFloat" : name; var s = style.getComputedStyle(n); // 若是指定的屬性名稱,調用_toStyleValue方法。 return (l == 1) ? s : _toStyleValue(n, name, s[name] || n.style[name]); /* CSS2Properties||String||Number */ };
dojo中對於opacity作了兼容性處理,這裏咱們只要知道原理便可,想詳細瞭解的同窗能夠本身查看dojo源碼:
var astr = "DXImageTransform.Microsoft.Alpha"; var af = function(n, f){ try{ return n.filters.item(astr); }catch(e){ return f ? {} : null; } }; var _getOpacity = has("ie") < 9 || (has("ie") < 10 && has("quirks")) ? function(node){ try{ return af(node).Opacity / 100; // Number }catch(e){ return 1; // Number } } : function(node){ return getComputedStyle(node).opacity; }; var _setOpacity = has("ie") < 9 || (has("ie") < 10 && has("quirks")) ? function(/*DomNode*/ node, /*Number*/ opacity){ if(opacity === ""){ opacity = 1; } var ov = opacity * 100, fullyOpaque = opacity === 1; // on IE7 Alpha(Filter opacity=100) makes text look fuzzy so disable it altogether (bug #2661), // but still update the opacity value so we can get a correct reading if it is read later: // af(node, 1).Enabled = !fullyOpaque; if(fullyOpaque){ node.style.zoom = ""; if(af(node)){ node.style.filter = node.style.filter.replace( new RegExp("\\s*progid:" + astr + "\\([^\\)]+?\\)", "i"), ""); } }else{ node.style.zoom = 1; if(af(node)){ af(node, 1).Opacity = ov; }else{ node.style.filter += " progid:" + astr + "(Opacity=" + ov + ")"; } af(node, 1).Enabled = true; } if(node.tagName.toLowerCase() == "tr"){ for(var td = node.firstChild; td; td = td.nextSibling){ if(td.tagName.toLowerCase() == "td"){ _setOpacity(td, opacity); } } } return opacity; } : function(node, opacity){ return node.style.opacity = opacity; };
經過上面代碼咱們能夠看到,若是沒有獲取特定屬性直接返回getComputedStyle方法獲得的結果,若是指明特定屬性則調用_toStyleValue方法, 該方法決定將哪些值轉化成數字:
var _pixelNamesCache = { left: true, top: true }; // 若是獲取的屬性符合這個正則表達式,將他們放到_pixelNamesCache中,將獲得的結果轉化成數字 var _pixelRegExp = /margin|padding|width|height|max|min|offset/; // |border function _toStyleValue(node, type, value){ //TODO: should we really be doing string case conversion here? Should we cache it? Need to profile! type = type.toLowerCase(); if(has("ie") || has("trident")){ //ie瀏覽器中若是width或height獲得的是auto,使用offsetWidth或者offsetHeight if(value == "auto"){ if(type == "height"){ return node.offsetHeight; } if(type == "width"){ return node.offsetWidth; } } // 對fontWeight的處理 if(type == "fontweight"){ switch(value){ case 700: return "bold"; case 400: default: return "normal"; } } } //若是符合正則,則放入_pixelNamesCache中,將獲得的結果轉化成數字 if(!(type in _pixelNamesCache)){ _pixelNamesCache[type] = _pixelRegExp.test(type); } return _pixelNamesCache[type] ? toPixel(node, value) : value; }
有了以上基礎,設置就簡單許多:
style.set = function setStyle(/*DOMNode|String*/ node, /*String|Object*/ name, /*String?*/ value){ var n = dom.byId(node), l = arguments.length, op = (name == "opacity"); // 對float屬性的處理 name = _floatAliases[name] ? "cssFloat" in n.style ? "cssFloat" : "styleFloat" : name; // 處理opacity屬性 if(l == 3){ return op ? _setOpacity(n, value) : n.style[name] = value; // Number } // 若是一次設置多個屬性,將他們分別處理; for(var x in name){ style.set(node, x, name[x]); } // 返回樣式的計算值 return style.getComputedStyle(n); };
對於多個屬性處理的這部分,最好的方式是使用cssText一次設置多個值:style.cssText = style.cssText+"拼接後的樣式字符串"。這樣瀏覽器只須要從新繪製一次便可應用多種樣式。而不是每次設置style都要重繪一次(有的瀏覽器能夠作優化處理)。固然使用cssText方式,一來在ie8中並不支持,而來若是要從新覆蓋一個樣式屬性咱們還須要作一些處理。
以上部分就是今天的博客內容,若是您以爲這篇文章對您有幫助,請不吝點擊下方推薦,您的鼓勵是我分享的動力!!!