拋磚引玉
很多前端類庫(比如dojo與JQuery)在涉及dom操作時都會見到兩個模塊:attr、prop。某天代碼復查時,見到一段為某節點設置文本的代碼:
attr.set(node, 'innerText', 'Hello World!')
這段代碼執行后並未生效,雖說innerText不是標准屬性,尚未被ff支持,可用的是chrome,這個屬性是被支持的。既然顯示的文本沒變,那就查看一下元素吧。
innerText被添加到了html標簽上,而換成prop模塊后,成功的為節點替換文本。
以上的這個小案例就涉及到了DOM操作時常常被忽略的一個問題:特性與屬性的區別
返本求源
在DOM中,特性指的是html標簽上的屬性,比如:
Property是對於某一類型特征的描述。可以這樣理解,在DOM元素中可以通過點語法訪問,又不是標准特性的都可以成為屬性。
DOM中所有的節點都實現了Node接口。Node接口是在DOM1級中定義的,其中定義了一些用來描述DOM節點的屬性和操作方法。
常見的nodeType、nodeValue、節點關系(parentNode、childNodes、firstChild、lastChild、previousSibling、nextSibling等)都屬於Node接口定義的屬性。對於Node接口的具體實現者,HTMLElement不僅繼承了這些屬性,還擁有五個wac規范中的五個標准特性:id、title、lang、dir、class和一個屬性:attributes。
每一個元素都有一個或多個特性,這些特性的用途是給出相應元素或其內容的附加信息。通過DOM元素直接操作特性的的方法有三個:
- getAttribute(attrName)
- setAttribute(attrName, value)
- removeAttribute(name)
這三個方法都可以操作自定義特性。但是只有公認的(非自定義)特性才會以屬性的形式添加到DOM對象中,以屬性方式操作這些特性會被同步到html標簽中。HTMLElement的五個特性都有相應屬性與其對待:id、title、lang、dir、className。在DOM中以屬性方式操作這幾個特性會同步到html標簽中。
不過,HTML5規范對自定義特性做了增強,只要自定義特性以"data-attrName"的形式寫入到html標簽中,在DOM屬性中就可以通過element.dataset.attrName的形式來訪問自定義特性,如:
<input type="text" name="as_q" class="box" id="searched_content" title="在此輸入搜索內容。" disabled="false" data-ff="fsdf"> seh.dataset.ff
元素的特性在DOM中以Attr類型來表示,Attr類型也實現了Node接口。Attr對象有三個屬性:name、value、specified。其中,name是特性的名稱,value是特性值,specified是一個布爾值,用來指示該特性是否被明確設置。
document.createAttribute方法可以用來創建特性節點。例如,要為元素添加align特性可以使用如下方法:
ar attr = document.createAttribute('align') attr.value = 'left' seh.setAttributeNode(attr)
要將新創建的特性添加到元素上,必須使用元素的setAttributeNode方法。添加特性后,特性會反映在html標簽上:
注意,盡管特性節點也實現了Node接口,但特性卻不被認為是DOM文檔樹的一部分。
在所有的DOM節點中attributes屬性是Element類型所獨有的的屬性。從技術角度來說,特性就是存在於元素的attributes屬性中的節點。attributes屬性屬於NamedNodeMap類型的實例。元素的每一個特性節點都保存在NamedNodeMap對象中。NamedNodeMap類型擁有如下方法:
- getNamedItem(name):返回特性名為name的特性節點
- removeNamedItem(name):刪除特性名為name的特性節點
- setNamedItem(attr):像元素中添加一個特性節點
- item(pos):返回位於數組pos處的節點
獲取、設置、刪除元素節點可以如下方式:
element.attributes.getNamedItem('align') //獲取 var attr = document.createAttribute('align'); attr.value = 'right'; element.attributes.setNamedItem(attr); //添加 element.attributes.removeNamedItem('align'); //刪除
實際應用中並不建議使用特性節點的方式,而getAttribute、setAttribute、removeAttribute方法遠比操作特性節點更方便。
DOM、attributes、Attr三者關系應該這么畫:
應用總結
基於以上DOM基礎知識和實際工作經驗,我將特性和屬性的區別聯系總結如下:
- 屬性以及公認特性可以通過點語法訪問;html5規范中,data-*形式的自定義特性可以通過element.dataset.*的形式來訪問,否則用getAttribute
- 特性值只能是字符串,而屬性值可以是任意JavaScript支持的類型
- 幾個特殊特性:
- style,通過getAttrbute和setAttribute來操作這個特性只能得到或設置字符串;而已屬性方式來操作就是在操作CSSStyleDeclaration對象
- 事件處理程序,通過特性方式得到和傳遞的都只是函數字符串;而已屬性方式操作的是函數對象
- value,對於支持value的元素,最好通過屬性方式操作,而且操作不會反映在html標簽上
seh.value = 10 <input type="text" name="as_q" class="box" id="searched_content" title="在此輸入搜索內容。" disabled="false" data-ff="fsdf" align="left">
- href,通過屬性方式設置可以反映到html標簽上,但用過點語法和getAttribute能夠取到的值並不一定相同
<a href="/jsref/prop_checkbox_tabindex.asp" id="tabI">tabIndex</a> link.getAttribute('href') // "/jsref/prop_checkbox_tabindex.asp" link.href // "http://www.w3school.com.cn/jsref/prop_checkbox_tabindex.asp"
- disabled和checked,對於支持這兩個特性的元素來說,他們在html標簽中都是無狀態的,只要有獨立的標簽屬性在以點語法訪問時就返回true,如果html標簽屬性不存在,則以點語法訪問時就是false
-
<input type="text" name="as_q" class="box" id="searched_content" title="在此輸入搜索內容。" disabled="false" data-ff="fsdf" align="left"> seh.disabled // true seh.disabled = false <input type="text" name="as_q" class="box" id="searched_content" title="在此輸入搜索內容。" data-ff="fsdf" align="left">
如果您覺得這篇文章對您有幫助,請不吝點擊右下方“推薦”,謝謝~