1. 程式人生 > >小白讀《JavaScript高階程式設計》DOM基礎部分

小白讀《JavaScript高階程式設計》DOM基礎部分

DOM

DOM(文件物件模型)是針對HTML和XML文件 的一個API(應用程式程式設計介面)。

節點層次

DOM可以將任何HTML或XML文件描繪成一個由多層節點構成的結構。
每個文件只能有一個文件元素,在HTML頁面中,文件元素始終都是<html>元素。
總共有12種節點型別:
示例圖片3

Node型別

DOM1級定義了一個Node介面,該介面將由DOM中的所有節點型別實現。
JavaScript中的所有節點型別都繼承自Node型別。
nodeType屬性:用於表明節點的型別。
12個數值 常量來表示節點型別,任何節點型別必居其一。

  • Node.ELEMENT_NODE(1);
  • Node.ATTRIBUTE_NODE(2);
  • Node.TEXT_NODE(3);
  • Node.CDATA_SECTION_NODE(4);
  • Node.ENTITY_REFERENCE_NODE(5);
  • Node.ENTITY_NODE(6);
  • Node.PROCESSING_INSTRUCTION_NODE(7);
  • Node.COMMENT_NODE(8);
  • Node.DOCUMENT_NODE(9);
  • Node.DOCUMENT_TYPE_NODE(10);
  • Node.DOCUMENT_FRAGMENT_NODE(11);
  • Node.NOTATION_NODE(12)。

nodeName和nodeValue屬性

瞭解節點的具體資訊。

節點關係

每個節點都有一個childNodes屬性,其中儲存著一個NodeList物件。
NodeList物件:一種類陣列的物件(不是陣列,但是有length)。

通用的將NodeList物件轉為陣列的方法:

function converToArray(nodes) {
	var array = null;
	try {
		array = Array.prototype.slice.call(nodes,0);		//針對非IE瀏覽器
	} catch (ex) {
		array = new Array();
		for (var i = 0,len = nodes.length; i < len; i++) {
			array.push(nodes[i]);
		}
	}
	return array;
}

每個節點都有一個parentNode屬性,該屬性指向文件樹中的父節點。
對於同胞節點,通過使用列表中每個節點的previousSibling(上一個節點)和nextSibling(下一個節點)屬性,可以訪問同一列表中的其他節點。

父節點的firstChild和lastChild屬性分別指向其childNodes列表中的第一個和最後一個節點。
示例圖片4

hasChildNodes()方法:返回是否有位元組點,Boolean型別。
每個節點都有的屬性:ownerDocument:該屬性指向表示整個文件的文件節點。

操作節點

appendChild()方法:用於向childNodes列表的末尾新增一個節點。
appendChild()返回新增的節點。
如果appendChild()中的節點已經是文件的一部分了,就將該節點從原來位置轉移到新位置。

insertBefore()方法:接受兩個引數:要插入的節點和作為參照的節點。
插入節點後,被插入的節點會變成參照節點的前一個同胞節點(previousSibling),同時被方法返回。
如果參照節點為null,則同appendChild()方法。

replaceChild()方法:接受兩個引數:要插入的節點和要替換的節點。

removeChild()方法:接受一個引數,即是要移除的節點。

其他方法

兩個所有型別的節點都有的方法:
cloneNode():用於建立呼叫這個方法的節點的一個完全相同的副本。
接受一個布林值引數,表示是否執行深複製。
true:深複製,複製節點及其整個子節點樹。
false:淺複製,只複製節點本身。

normalize():這個方法唯一的作用就是處理文件樹中的文字節點。
刪除文字,合併相鄰文字節點。

Document型別

Document節點具有下列特徵:

  • nodeType的值為9;
  • nodeName的值為"#document";
  • nodeValue的值為null;
  • parentNode的值為null;
  • ownerDocument的值為null;
  • 其子節點可能是一個DocumentType(最多一個)、Element(最多一個)、ProcessingInstruction或Comment。

文件的子節點

documentElement屬效能更快捷、更直接地訪問HTML中的<html>元素。
獲取body元素:document.body
獲取<!DOCTYPE>標籤:document.doctype

文件資訊

類似的還有:
document.title;
document.URL;(http獲得的頁面的URL)
document.domain(域名)

查詢元素

兩個方法:

  • getElementById():通過id屬性(怪癖:name屬性也會被呼叫)
  • getElementsByTagName():通過標籤名。

HTMLDocument型別獨有的方法:
getElementsByName():通過name屬性。

特殊集合

都是HTMLCollection物件:

  • document.anchors:所有帶name特性發<a>元素。
  • document.applets:文件中所有的<applet>元素。
  • document.forms
  • document.images
  • document.links:文件中所有帶href特性的<a>元素。

DOM一致性檢測

document.implementation規定了一個方法:hasFeature()。

var hasXmlDom = document.implementation。hasFeature("XML","1.0");

文件寫入

4個方法:

  • write():接受一個字串
  • writeln():接受一個字串
  • open():開啟網頁的輸出流
  • close():關閉網頁的輸出流

Element型別

  • nodeType的值為1
  • nodeName的值為元素的標籤名
  • nodeValue的值為null
  • parentNode可能是Document或Element;
  • 其子節點可能是Element、Text、Comment、ProcessingInstruction、CDATASection或EntityReference。

在HTML中,標籤名始終都以大寫表示,而在XML(有時候也包括XHTML)中,標籤名則始終會與原始碼中的保持一致。

element.tagName.toLowerCase() == "div"

HTML元素

所有HTML元素都由HTMLElement型別表示。

  • id,元素在文件中的唯一識別符號。
  • title,有關元素的附加說明資訊,一般通過工具提示條顯示出來。
  • lang,元素內容的語言程式碼,很少使用。
  • dir,語言的方向,ltr、rtl。
  • className,與元素的class特性對應。

取得特性

每個元素都有一個或多個特性,這些特性的用途是給出相應元素或其內容的附加資訊。
操作特性的DOM方法主要有三個:

  • getAttribute():引數是特性名的字串。
  • setAttribute():同上
  • removeAttribute():同上

兩類特殊的特性:style和onclick。

設定特性

setAttribute(),替換或者建立。
這個方法設定的特性名會統一轉換為小寫形式。

attributes屬性

Element型別是使用attributes屬性的唯一一個DOM節點型別。
attributes屬性中包含一個NameNodeMap。
NameNodeMap物件擁有的方法:

  • getNameItem(name):返回nodeName屬性等於name的節點。
  • removeNamedItem(name)
  • setNamedItem(name)
  • item(pos)

為特性設定新值:

element.attributes["id"].nodeValue = "someOtherId";

建立元素

document.createElement()方法。
引數是要建立元素的標籤名。HTML忽略大小寫,XML區分大小寫。

把新元素新增到文件樹:
appendChild()、insertBefore()、replaceChild()。

注意點:

  1. 不能設定動態建立的<iframe>元素的name特性。
  2. 不能通過表單的reset()方法重設動態建立的<input>元素。
  3. 動態建立的type特性值為"reset"的<button>元素重設不了表單。
  4. 動態建立的一批name相同的單選框彼此毫無關係。

元素的子節點

元素可以有任意數目的子節點和後代節點。
這些子節點有可能是元素、文字節點、註釋或處理指令。

Text型別

  • nodeType的值為3
  • nodeName的值為"#text"
  • nodeValue的值為節點所包含的文字
  • parentNode是一個Element
  • 不支援(沒有)子節點。

操作節點中的文字:

  • appendData(text):將text新增到節點的末尾
  • deleteData(offset,count):從offset指定的位置開始刪除count個字元。
  • insertData(offset,text):在offset指定的位置插入text
  • replaceData(offset,count,text):用text替換從offset指定的位置開始到offset+count為止的文字。
  • splitText(offset):從offset指定的位置將當前文字節點分成兩個文字節點。
  • substringData(offset,count):提取從offset指定的位置開始到offset+count為止的字串。

還有個length屬性

建立文字節點

document.createTextNode()方法。

規範化文字節點

normalize()方法
父節點使用,子節點中多個文字節點合併為一個。

分割文字節點

splitText()方法。
引數:一個數值代表要分割的位置。
把一個節點分為兩個。

Comment型別

  • nodeType的值為8
  • nodeName的值為"#comment"
  • nodeValue的值是註釋的內容
  • parentNode 可能是Document或Element
  • 不支援(沒有)子節點。

Coment型別與Text型別繼承自相同的基類(所以,你懂的,很多前面提到的方法可以用)。
document.createComment()

CDATASection型別

只針對基於XML的文件。類似Comment,nodeType值為4。

DocumentType型別

並不常用。包含著與文件的doctype有關的所有資訊。

  • nodeType的值為10
  • nodeName的值為doctype的名稱
  • nodeValue的值為null
  • parentNode是Document
  • 不支援(沒有)子節點

DocumentFragment型別

"輕量級"文件。

  • nodeType值11
  • nodeName:"#document-fragment"
  • nodeValue:null
  • parentNode:null
  • 子節點可以是:Element、ProcessingInstruction、Comment、Text、CDATASection或EntityReference。

document.createDocumentFragment()方法。

Attr型別

  • nodeType:2
  • nodeName:特性的名稱
  • nodeValue:特性的值
  • parentNode:null
  • 在HTML中不支援(沒有)子節點。
  • 在XML中子節點可以是Text或EntityReference。

3個屬性:name、value、specified(布林值,區別在程式碼中指定的還是預設的)。
程式碼演示:

var attr = document.createAttribute("align");
attr.value = "left";
element.setAttributeNode(attr);
alert(element.atrributes["align"].value);		//"left"
alert(element.getAtrributeNode("align").value);		//"left"
alert(element.getAtrribute("align"));				//"left"

DOM操作技術

瀏覽器中充斥著隱藏的陷阱和不相容問題。

動態指令碼

在頁面載入時不存在,但將來的某一時刻通過修改DOM動態新增的指令碼。
建立動態指令碼兩種方式:插入外部檔案和直接插入JavaScript程式碼。
封裝的方法實現載入外部JavaScript檔案:

function loadScript(url) {
	var script = document.createElement("script");
	script.type = "text/javascript";
	script.src = url;
	document.body,appendChild(script);
}

直接插入封裝的函式:

function loadScriptString(code) {
	var script = document.createElement("script");
	script.type = "text/javascript";
	try {
		script.appendChild(document.createTextNode(code));
	}catch(ex) {
		script.text = code;
	}
	document.body.appendChild(script);
}

動態樣式

封裝的載入樣式的方法:

function loadStyles(url) {
	var link = document.createElement("link");
	link.rel = "stylessheet";
	link.type = "text/css";
	link.href = url;
	var head = document.getElementsByTagName("head")[0];
	head.appendChild(link);
}

直接寫程式碼封裝的方法:

function loadStylesString(css) {
	var style = document.createElement("style");
	style.type = "text/css";
	try {
		style.appendChild(document.createTextNode(css));
	} catch (ex) {
		style.styleSheet.cssText = css;
	}
	var head = document.getElementsByTagName('head')[0];
	head.appendChild(style);
}

操作表格

<table>元素是HTML中最複雜的結構之一。
正常寫需要冗長的程式碼。
使用HTMLDOM提供的方法可以簡化。
例:要建立下面結構:

<table border="1" width="100%">
	<tbody>
		<tr>
			<td>Cell 1,1</td>
			<td>Cell 2,1</td>
		</tr>
		<tr>
			<td>Cell 1,2</td>
			<td>Cell 2,2</td>
		</tr>
	</tbody>
</table>

DOM程式碼:

//建立table
var table = document.createElement("table");
table.border = 1;
table.width = "100%";

//建立tbody
var tbody = document.createElement("tbody");
table.appendChild(tbody);
//建立第一行
tbody.insertRow(0);
tbody.rows[0].insertCell(0);
tbody.rows[0].cells[0].appendChild(document.createTextNode("Cell 1,1"));
tbody.rows[0].insertCell(1);
tbody.rows[0].cells[1].appendChild(document.createTextNode("Cell 2,1"));
//建立第二行
tbody.insertRow(1);
tbody.rows[1].insertCell(0);
tbody.rows[1].cells[0].appendChild(document.createTextNode("Cell 1,2"));
tbody.rows[1].insertCell(1);
tbody.rows[1].cells[1].appendChild(document.createTextNode("Cell 2,2"));
//將表格新增到文件主體中
document.body.appendChild(table);

使用NodeList

三個”動態的”集合:NameNodeMap、HTMLCollection和NodeList。
每當文件結構發生變化時,都會得到更新。