一、DOM特性和DOM屬性
attribute(特性),是我們賦予某個事物的特質或對象,attribute是HTML標簽上的特性,它的值只能夠是字符串
property(屬性),是早已存在的不需要外界賦予的特質,property是DOM中的屬性,是JavaScript里的對象
在訪問元素特性值時有兩種方式:
1. 傳統DOM方法getAttribute和setAttribute。
2. 使用DOM對象上與之對應的屬性。
例如通過兩種方式獲取id的值:
e.getAttribute('id');
e.id;

1)跨瀏覽器命名
特性和屬性命名之間的差異會更多。
在大多數瀏覽器中可以用class獲取到class特性,但IE卻要使用className。
2)命名限制
特性表示為傳遞給DOM方法的字符串,其命名規范是非常自由的。
而屬性名稱,由於可以作為標識符使用點表示法進行訪問,所以其命名規范更受限制。

3)HTML和XML之間的差異
在處理一個XML DOM的時候,不會在元素上自動創建屬性值來表示特性值。
因此,我們需要使用傳統的DOM特性方法獲取特性的值。
elem.ownerDocument只讀屬性會返回當前節點的頂層的 document 對象。
function isXML(elem) {
return (elem.ownerDocument || elem.documentElement).nodeName.toLowerCase() !== 'html';
}
4)自定義特性的行為
要想訪問自定義特性值,需要使用DOM方法getAttribute()與setAttribute()。
在HTML5中,對所有的自定義特性使用“data-”前綴。
5)性能注意事項
總的來說,屬性的訪問速度比相應DOM特性方法的訪問速度要快,特別是在IE瀏覽器中。
下面做個測試,分別用兩種方式讀取和設置500W次。可以在不同瀏覽器中點開這個地址來查看測試結構。
下面的截圖是在Chrome中的結果:

二、跨瀏覽器的Attribute問題
1)DOM中的id/name膨脹
5大瀏覽器都會將表單input元素的id和name特性作為<form>元素的屬性值進行引用。
產生的這些屬性,會主動覆蓋form元素上已經存在的同名屬性。
此外,IE瀏覽器不僅會替換屬性值,甚至還會替換該屬性值上的特性值。
<form id="testForm" action="/">
<input type="text" id="id"/>
<input type="text" name="action"/>
</form>
var form = document.getElementById('testForm');
assert(form.id === 'testForm', "the id property is untouched");
assert(form.action === '/', "the action property is untouched");
assert(form.getAttribute('id') === 'testForm', "the id attribute is untouched");
assert(form.getAttribute('action') === '/', "the action attribute is untouched");

在所有的現代瀏覽器中,由於這些input定義的id和name的值,表單的id和action屬性都會被input元素的引用所替代。
解決方法是獲取描述元素特性本身的原始DOM節點,該節點沒有被瀏覽器修改:
var action = element.getAttributeNode('action').nodeValue;
2)URL規范化
在訪問一個引用了URL屬性時(例如src、href或action),該URL值會自動將原始值轉換成完整規范的URL。
<a href="listing-11.5.html" id="testSubject">Self</a>
var link = document.getElementById('testSubject');
var linkHref = link.getAttributeNode('href').nodeValue; //#1
assert(linkHref === 'listing-11.5.html', 'link node value is ok');
assert(link.href === 'listing-11.5.html', 'link property value is ok');
assert(link.getAttribute('href') == linkHref, 'link attribute not modified');

3)style特性
HTML DOM元素有一個style屬性,通過該屬性我們能獲取元素的樣式信息,例如element.style.color。
<span style="color:red"></span>
如果要獲取“color:red”字符串,那么style屬性沒用,得用getAttribute('style')方法獲取。
但IE中得用element.style.cssText獲取。
4)節點名稱
在HTML文檔中,nodeName屬性返回的名稱將是大寫(例如HTML、BODY)。
在XML或XHTML文檔中,nodeName返回的名稱是用戶指定的名稱,可以大寫、小寫或混合。
三、令人頭疼的樣式特性
1)樣式在何處
<style>
div { font-size: 1.8em; border: 0 solid gold; }
</style>
<div style="color:#000;" title="Ninja power!">
忍者
</div>
var div = document.getElementsByTagName("div")[0];
assert(div.style.color == 'rgb(0, 0, 0)' || div.style.color == '#000','color was recorded');
assert(div.style.fontSize == '1.8em', 'fontSize was recorded');
assert(div.style.borderWidth == '0', 'borderWidth was recorded');
div.style.borderWidth = "4px"; //#6
assert(div.style.borderWidth == '4px', 'borderWidth was replaced');

1. 大多數顏色都會轉換成RGB顏色符號,有一些會轉換為顏色的名稱。
2. font-size和border都被記錄在了style標簽內,樣式是繼承獲取的,但div.style屬性中沒有獲取到。
3. 一個元素的style屬性中的任何一個樣式的優先級都要高於樣式表所繼承的樣式(即便使用了“!important”注解規則)。
2)樣式屬性命名
CSS特性將多余一個單詞的用連字符分隔,例如font-size、font-weight等。
在JS中可以用帶有連字符的樣式名稱,但不能使用點運算符來訪問樣式了。
var size = element.style['font-size'];//允許 var size = element.style.font-size;//不允許 var size = element.style.fontSize;//允許
在JS中多個單詞的CSS樣式名稱用駝峰的方式命名,例如fontSize、fontWeight。
具體的CSS樣式表對應屬性可以參考《CSS Properties Reference》
3)設置多個樣式屬性
不能通過直接給style屬性設置字符串(如:elt.style = "color: blue;")來設置style,因為style應被當成是只讀的。
設置多個屬性可以用cssText或setAttribute,其中cssText會將重復屬性覆蓋屌。
elt.style.cssText = "color: blue"; // 設置多個樣式屬性 當帶前綴的時候-webkit-transform:rotate(0deg),會過濾掉-webkit,只能用下面的方式
elt.setAttribute("style", "color: blue"); // 設置多個樣式屬性
4)float樣式屬性
float是JS中的保留關鍵字,瀏覽器需要提供另外一個替代名稱。
大部分瀏覽器使用cssFloat,但IE使用styleFloat。
5)像素值的轉換過程
為style屬性設置數字時,必須要指定單位,以便在所有的瀏覽器上都能使用。
element.style.height = '10px';//安全 element.style.height = 10;//不安全
6)測量元素的高度和寬度
offsetHeight和offsetWidth可以獲取元素的高度和寬度,不過這兩個屬性值包括了padding值,更多元素尺寸屬性可以參考《JavaScript中尺寸、坐標》
但如果元素隱藏(例如display:none),獲取到的數值都是0。對於隱藏元素可以用如下的方法:

可以查看在線demo實例:


“Pole”是顯示的圖片,就是那個忍者。
而“Shuriken”是隱藏的圖片,一開始是獲取不到寬度的,在使用了上面的技巧后就能獲取到了。
7)通過opacity看透明度
所有現代瀏覽器,包括IE9支持opacity屬性,但IE9之前的版本需要使用專用的alpha過濾法。
opacity: .5; filter: alpha(opacity=50)
支持opacity的瀏覽器,總會將值規范為小於1.0且以0開頭的值。
例如“opacity:.5”,那么支持的將返回“0.5”,不支持的將返回“.5”。
通過特性仿真,可以判斷瀏覽器是否支持opacity。
//特性仿真檢測
var div = document.createElement("div"); //#1
div. setAttribute('style','opacity:.5');
var OPACITY_SUPPORTED = div.style.opacity === "0.5";
assert(OPACITY_SUPPORTED, "Opacity is supported.");
8)顏色屬性
通過不同的計算樣式方法訪問這些顏色值的時候,各種瀏覽器的返回值幾乎都不一致。

下面是一個在線demo,在不同瀏覽器中展示的顏色值:
| IE8 |
Firefox | Chrome |
![]() |
![]() |
![]() |
| IE8不支持RGBA和HSL格式 | Firefox不僅保留了顏色名稱, 而且標准顏色是RGB和RGBA格式 |
Webkit瀏覽器(Chrome、Safari) 標准顏色是RGB和RGBA格式 |
四、獲取計算樣式
1)window.getComputedStyle()與element.currentStyle
一個元素的計算樣式(computed style)都是應用在該元素上的所有樣式組合。
這些樣式包括樣式表、元素的style特性,以及腳本對style屬性的各種操作。
現代瀏覽器(包括IE9)的實現方法為:window.getComputedStyle(),返回接口提供了一個getPropertyValue()的方法。
IE9之前的版本,通過附加到所有元素上的currentStyle屬性,表現和style屬性一樣。
/**
* property可以傳入駝峰或分隔符方式
*/
function fetchComputedStyle(element, property) { //#3
//現代瀏覽器 包括IE9
if (window.getComputedStyle) {
var computedStyles = window.getComputedStyle(element); //#4
if (computedStyles) { //#5
property = property.replace(/([A-Z])/g, '-$1').toLowerCase();
return computedStyles.getPropertyValue(property);//getPropertyValue中需要傳入分隔符字符串,例如font-size
}
} else if (element.currentStyle) { //IE9以下
property = property.replace(
/-([a-z])/ig,
function(all, letter) {
return letter.toUpperCase();
});
return element.currentStyle[property];
}
}




