10 DOM

本章內(nèi)容

  • 理解包含不同層次節(jié)點的 DOM
  • 使用不同的節(jié)點類型
  • 克服瀏覽器兼容性問題及各種陷阱

DOM 是針對 HTML 和 XML 文檔的一個 API。DOM 描繪了一個層次化的節(jié)點樹,允許開發(fā)人員添加、移除和修改頁面的某一部分。本章主要討論與瀏覽器中的 HTML 頁面相關(guān)的 DOM1 級的特性和應(yīng)用,以及 JavaScript 對 DOM1 級的實現(xiàn)。

注意,IE 中的所有 DOM 對象都是以 COM 對象的形式實現(xiàn)的。這意味著 IE 中的 DOM 對象與原生 JavaScript 對象的行為活動特點并不一致。

10.1 節(jié)點層次

DOM 可以將任何 HTML 或 XML 文檔描繪成一個由多層節(jié)點構(gòu)成的結(jié)構(gòu)。

10.1.1 Node 類型

除了 IE 之外,在其他所有瀏覽器中都可以訪問到這個類型。 JavaScript 中的所有節(jié)點類型都繼承Node 類型,因此所有節(jié)點類型都共享著相同的基本屬性和方法。
每個節(jié)點都有一個 nodeType屬性,用于表明節(jié)點的類型。節(jié)點類型由在Node類型中定義的下列 12 個數(shù)值常量來表示。

  • 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)

通過比較上面這些常量,可以很容易地確定節(jié)點類型。如:

if (someNode.nodeType == Node.ELEMENT_NODE) {
  alert("Node is an element");
}

由于 IE 沒有公開Node類型的構(gòu)造函數(shù),因此上面的代碼在 IE 中會導(dǎo)致錯誤。為確??鐬g覽器兼容,最好還是將nodeType屬性與數(shù)字值進(jìn)行比較:

if (someNode.nodeType == 1) {
  alert("Node is an element");
}

并非所有節(jié)點類型都受到 Web 瀏覽器的支持。開發(fā)人員最常用的就是元素和文本節(jié)點。

  1. nodeName 和 nodeValue 屬性
    在使用這倆屬性之前,最好先檢測一下節(jié)點的類型。
if (someNode.nodeType == 1) {
  name = someNode.nodeName;
}

對于元素節(jié)點,nodeName中保存的始終都是元素的標(biāo)簽名,而nodeValue的值則始終未null。

  1. 節(jié)點關(guān)系
    每個節(jié)點都有一個childNodes屬性,其中保存著一個NodeList對象。它是一種類數(shù)組對象,用于保存一組有序的節(jié)點,可以通過位置來訪問這些節(jié)點。它實際上是基于 DOM 結(jié)構(gòu)動態(tài)執(zhí)行查詢的結(jié)果,因此 DOM 結(jié)構(gòu)的變化能夠自動反映在NodeList對象中。
var firstChild = someNode.childNodes[0];
var secondChild = someNode.childNodes.item(1);
var count = someNode.childNodes.length;

其中,length屬性表示的是訪問NodeList的那一刻,其中包含的節(jié)點數(shù)量。對arguments對象使用Array.prototype.slice()方法可以將其轉(zhuǎn)換為數(shù)組。也可以將NodeList對象轉(zhuǎn)換為數(shù)組。

//在 IE8 及之前版本中無效
var arrayOfNodes = Array.prototype.slice.call(someNode.childNodes,0);

要想在 IE 中將NodeList轉(zhuǎn)換為數(shù)組,必須手動枚舉所有成員。

function convertToArray(nodes) {
  var array = null;
  try {
    array = Array.prototype.slice.call(nodes, 0);
  } catch(ex) {
    array = new Array();
    for (var i=0,len=nodes.length;i<len;i++) {
      array.push(nodes[i]);
    }
  }
}

每個節(jié)點都有一個parentNode屬性,該屬性指向文檔樹中的樹節(jié)點。包含在childNodes列表中的所有節(jié)點都具有相同的父節(jié)點,因此它們的parentNode屬性都指向同一個節(jié)點。此外,包含在childNodes列表中的每個節(jié)點相互之間都是同胞節(jié)點。可以使用previousSiblingnextSibling屬性,可以訪問同一列表中的其他節(jié)點。

if (someNode.nextSibling === null){
  alert("Last node in the parent's childNodes list");
} else if (someNode.previousSibling === null) {
  alert("First node in the parent childNodes list.");
}

父節(jié)點的firstChildlastChild屬性分別子節(jié)點列表中的第一個和最后一個節(jié)點。
另外,hasChildNodes()也是一個非常有用的方法,這個方法在節(jié)點包含一或多個子節(jié)點的情況下返回true。
所有節(jié)點都有的最后一個屬性是ownerDocument,該屬性指向表示整個文檔的文檔節(jié)點。這種關(guān)系表示的任何節(jié)點都屬于它所在的文檔,任何節(jié)點都不能同時存在于兩個或更多個文檔中。

雖然所有節(jié)點類型都繼承自Node,但并不是每種節(jié)點都有子節(jié)點。

  1. 操作節(jié)點
    其中,最常用的方法是appendChild(),用于向childNodes列表的末尾添加一個節(jié)點。更新完成后,appendChild()返回新增的節(jié)點。
var returnedNode = someNode.appendChild(newNode);
alert(returnedNode == newNode);  //true
alert(someNode.lastChild == newNode);  //true

如果傳入到appendChild()中的節(jié)點已經(jīng)是文檔中一部分了,那結(jié)果就是將該節(jié)點從原來的位置轉(zhuǎn)移到新位置。
如果需要把節(jié)點放在列表中的某個位置,而不是放在末尾,可以使用insertBefore()方法。這個方法接受兩個參數(shù):要插入的節(jié)點和作為參照的節(jié)點。如果參照節(jié)點是null,則放在末尾。

//插入后稱為最后一個字節(jié)點
returnedNode = someNode.insertBefore(newNode, null);
alert(newNode == someNode.lastChild);  //true
//插入后成為第一個子節(jié)點
var returnedNode = someNode.insertBefore(newNode, someNode.firstChild);
alert(returnedNode == newNode);  //true
alert(newNode == someNode.firstChild);  //true

replaceChild()方法接受倆參數(shù):要插入的節(jié)點和要替換的節(jié)點。要替換的節(jié)點將由這個方法返回并從文檔樹中被移除,同時由要插入的節(jié)點占據(jù)其位置。

//替換第一個子節(jié)點
var returnedNode = someNode.replaceChild(newNode,someNode.firstChild);
//替換最后一個節(jié)點
returnedNode = someNode.replaceChild(newNode, someNode.lastChild);

如果只想移除而非替換節(jié)點,可以使用removeChild()方法。這個方法接受一個參數(shù),即要移除的節(jié)點。

//移除第一個子節(jié)點
var formerFirstChild = someNode.removeChild(someNode.firstChild);
//移除最后一個子節(jié)點
var formerLastChild = someNode.removeChild(someNode.lastChild);

與使用replaceChild()方法一樣,通過removeChild()移除的節(jié)點仍然為文檔所有,只不過在文檔中已經(jīng)沒有了自己的位置。
要使用這幾個方法必須先取得父節(jié)點(使用parentNode屬性)。另,并不是所有類型的節(jié)點都有子節(jié)點。

  1. 其他方法
    有兩個方法是所有類型的節(jié)點都有的。第一個就是cloneNode(),用于創(chuàng)建調(diào)用這個方法的節(jié)點的一個完全相同的副本。cloneNode()方法接受一個布爾值參數(shù),表示是否執(zhí)行深復(fù)制。參數(shù)為true的情況下,執(zhí)行深復(fù)制,也就是復(fù)制節(jié)點及其整個子節(jié)點樹;參數(shù)為false的情況下,執(zhí)行淺復(fù)制,即只復(fù)制節(jié)點本身。復(fù)制后返回的節(jié)點副本屬于文檔所有,但并沒有為它指定父節(jié)點。因此,這個節(jié)點副本就成為了一個“孤兒”,除非通過appendChild()、insertBefore()replaceChild()將它添加到文檔中。

cloneNode()方法不會復(fù)制添加到 DOM 節(jié)點中的 JavaScript 屬性,例如事件處理程序等。IE 在此存在一個 bug,即它會復(fù)制事件處理程序,所以我們建議在復(fù)制之前最好先移除事件處理程序。

介紹的最后一個方法是normalize(),這個方法唯一的作用就是處理文檔樹中的文本節(jié)點。當(dāng)在某個節(jié)點上調(diào)用這個方法時,如果找到了空文本節(jié)點,則刪除它;如果找到相鄰的文本節(jié)點,則將它們合并為一個文本節(jié)點。

10.1.2 Document 類型

JavaScript 通過Document類型表示文檔。document對象是HTMLDocument(繼承自 Document 類型)的一個實例,表示整個 HTML 頁面。而且,document對象是window對象的一個屬性,因此可以將其作為全局對象來訪問。Document節(jié)點具有下列特征:

  • nodeType的值為 9;
  • nodeName的值為“#document”;
  • nodeValue的值為null;
  • parentNode的值為null
  • ownerDocument的值為null;
  • 其子節(jié)點可能是一個DocumentType(最多一個)、Element(最多一個)、ProcessingInstructionComment。

Document類型可以表示 HTML 頁面或者其他基于 XML 的文檔。不過,最常見的還是作為HTMLDocument實例的document對象。通過這個文檔對象,不僅可以取得與頁面有關(guān)的信息,而且還能操作頁面的外觀及其底層結(jié)構(gòu)。

  1. 文檔的子節(jié)點
    有兩個內(nèi)置的訪問其子節(jié)點的快捷方式。第一個就是documentElement屬性,該屬性始終指向 HTML 頁面中的<html>元素。另一個就是通過childNodes列表訪問文檔元素,但通過documentElement屬性則能更快捷、更直接地訪問該元素。如下所示:
var html = document.documentElement;
alert(html === document.childNodes[0]);  //true(false ?)
alert(html === document.firstChild);  //true (false ?)

作為HTMLDocument的實例,document對象還有一個body屬性,直接指向<body>元素。開發(fā)人員經(jīng)常要使用這個元素。

var body = document.body;  //取得引用

所有瀏覽器都支持document.documentElementdocument.body屬性。
另一個可能的子節(jié)點是DocumentType。通常將<!DOCTYPE>標(biāo)簽看成一個與文檔其他部分不同的實體,可以通過doctype屬性來訪問它的信息。

var doctype = document.doctype;

由于瀏覽器對document.doctype的支持不一致,因此這個屬性的用處很有限。
從技術(shù)上說,出現(xiàn)在<html>元素外的注釋應(yīng)該算是文檔的子節(jié)點。然而,不同的瀏覽器在是否解析這些注釋以及能否正確處理它們等方面,也存在很大差異。

  1. 文檔信息
    作為HTMLDocument的一個實例,document對象還有一些標(biāo)準(zhǔn)的Document對象所沒有的屬性。這些屬性提供一些網(wǎng)頁的一些信息。
//取得文檔標(biāo)題
var originalTitle = document.title;
//設(shè)置文檔標(biāo)題
document.title = "New page title";
//取得完整的 URL
var url = document.URL;
//取得域名
var domain = document.domain;
//取得來源頁面的 URL
var referrer = document.referrer;

只有domain是可以設(shè)置的。如果 URL 中包含一個子域名,例如 p2p.wrox.com,那么就只能將domain設(shè)置為"wrox.com"(URL 中包含“www”,如 www.wrox.com 時,也是如此)。不能將這個屬性設(shè)置為 URL 中不包含的域。
當(dāng)頁面中包含來自其他子域的框架或內(nèi)嵌框架時,能夠設(shè)置document.domain就非常方便了。由于跨域安全限制,來自不同子域的頁面無法通過 JavaScript 通信。而通過將每個頁面的document.domain設(shè)置為相同的值,這些頁面就可以互相訪問對方包含的JavaScript對象了。

  1. 查找元素
    第一個方法,getElementById,通過 ID 獲取該元素。
    另一個常用于取得元素引用的方法是getElementsByTagName,通過標(biāo)簽名取得元素,返回的是包含零或多個元素的NodeList。在 HTML 文檔中,這個方法會返回一個 HTMLCollection 對象。
var images = document.getElementByTagName('img');
alert(images.length);
alert(images[0].src);
alert(images.item(0).src);

HTMLCollection對象還有一個方法,namedItem(),使用這個方法可以通過元素的name特性取得集合中的項。

var myImage = images.namedItem("myImage");

還支持按名稱訪問項。

var myImage = images["myImage"];

HTMLCollection而言,我們可以向方括號中傳入數(shù)值或字符串形式的索引值。在后臺,對數(shù)值索引就會調(diào)用item(),而對字符串索引就會調(diào)用namedItem()。
要想取得文檔中的所有元素,可以向getElementsByTagName()中傳入"*"。在 JavaScript 及 CSS 中,星號(*)通常表示“全部”。

var allElements = document.getElementsByTagName("*");

第三個方法,也是只有HTMLDocument類型才有的方法,是getElementsByName()。

  1. 特殊集合
    還有一些特殊的集合,這些集合都是HTMLCollection對象,為訪問文檔常用的部分提供了快捷方式。
  2. DOM 一致性檢測
    由于 DOM 分為多個級別,也包含多個部分,因此檢測瀏覽器實現(xiàn)了 DOM 的哪些部分就十分必要。DOM1 級只為 document.implementation規(guī)定了一個方法,即hasFeatrue()
var hasXmlDom = document.implementation.hasFeature("XML", "3.0");

建議在多數(shù)情況下,在使用 DOM 的某些特殊功能之前,最好除了檢測hasFeature()之外,還同時使用能力檢測。

  1. 文檔寫入
    這個能力體現(xiàn)在下列 4 個方法中:write()、writeln()open()、close()。writeln()會在字符串的末尾添加一個換行符(\n)。
    方法openclose()分別用于打開和關(guān)閉網(wǎng)頁的輸出流。

嚴(yán)格型 XHTML 文檔不支持文檔寫入。對于那些按照 application/xml + xhtml 內(nèi)容類型提供的頁面,這兩個方法也同樣無效。

10.1.3 Element 類型

Element類型用于表現(xiàn) XML 或 HTML 元素。提供了對元素標(biāo)簽名、子節(jié)點及特性的訪問。Element節(jié)點具有以下特征:

  • nodeType的值為 1;
  • nodeName的值為元素的標(biāo)簽名;
  • nodeValue的值為null;
  • parentNode可能是DocumentElement;
  • 其子節(jié)點可能是Element、Text、Comment、ProcessingInstruction、CDATASectionEntityReference

要訪問元素的標(biāo)簽名,可以使用nodeName屬性,也可以使用tagName屬性。

var div = document.getElementById('myDiv');
alert(div.tagName);  //"DIV"
alert(div.tagName == div.nodeName);  //true

在 HTML 中,標(biāo)簽名始終都以全部大寫表示;而在 XML中,標(biāo)簽名則始終會與源代碼中的保持一致。最好是在比較之前將標(biāo)簽名轉(zhuǎn)換為相同的大小寫形式。

if (element.tagName.toLowerCase() == "div") {}
  1. HTML 元素
    所有 HTML 元素都由HTMLElement類型表示,不是直接通過這個類型,也是通過它的子類型來表示。HTMLElement類型直接繼承自Element并添加了一些屬性。添加的這些屬性分別對應(yīng)于每個 HTML 元素中都存在的下列標(biāo)準(zhǔn)特性。
  • id,元素在文檔中的唯一標(biāo)識符。
  • title,有關(guān)元素的附加說明信息,一般通過工具提示條顯示出來。
  • lang,元素內(nèi)容的語言代碼,很少使用。
  • dir,語言的方向,很少使用。
  • className,與元素的class特性對應(yīng),即為元素指定的 CSS 類。class是 ECMAScript 的保留字。
    上述屬性都可以用來取得或修改相應(yīng)的特性值。
var div = document.getElementById('myDiv');
alert(div.id);
alert(div.className);
alert(div.title);
alert(div.lang);
alert(div.dir);
div.id = 'someOtherId';
div.className = 'ft';
div.title = 'Some Other text';
div.lang = 'fr';
div.dir = 'rtl';
  1. 取得特性
    每個元素都有一或多個特性,這些特性的用途是給出相應(yīng)元素或其內(nèi)容的附加信息。操作特性的 DOM 方法主要有三個,分別是getAttribute()setArributeremoveAttribute()。
var div = document.getElementById('myDiv');
alert(div.getAttribute('id'));
alert(div.getAttribute('class'));
alert(div.getAttribute('title'));
alert(div.getAttribute('lang'));
alert(dib.getAttribute('dir'));

注意,傳遞給getAttribute()的特性名與實際的特性名相同。因此要想得到class特性值,應(yīng)該傳入class而不是className,后者只有在通過對象屬性訪問特性時采用。
通過getAttribute()方法也可以取得自定義特性(即標(biāo)準(zhǔn) HTML 語言中沒有的特性)的值。不過,特性的名稱是不區(qū)分大小寫的。另外,根據(jù) HTML5 規(guī)范,自定義特性應(yīng)該加上data-前綴以便驗證。
只有公認(rèn)的(非自定義)特性才會以屬性的形式添加到 DOM 對象中。
有兩類特殊的特性,它們雖然有對應(yīng)的屬性名,但屬性的值與通過getAttribute()返回的值并不相同。第一類特性就是style,用于通過 CSS 為元素指定樣式。使用getAttribute()返回的是 CSS 文本,而通過屬性訪問則會返回一個對象。
第二類是onclick這樣的事件處理程序。通過getAttribute()訪問時返回的是相應(yīng)代碼的字符串。而在訪問onclick屬性時,則會返回一個 JavaScript 函數(shù)。
由于存在這些差別。經(jīng)常不使用getAttribute(),而是只使用對象的屬性。只有在取得自定義特性值的情況下,才會使用getAttribute()方法。

  1. 設(shè)置特性
    setAttribute()該方法接受兩個參數(shù):要設(shè)置的特性名和值。如果特性已經(jīng)存在,setAttribute()會以指定的值替換現(xiàn)有的值;如果特性不存在,setAttribute()則創(chuàng)建該屬性并設(shè)置相應(yīng)的值。
div.setAttribute('id', 'someOtherId');
div.setAttribute('title', 'Some other text');
div.setAttribute('lang','fr');

直接給屬性賦值也可以設(shè)置特性的值。

div.id = "someOtherId";

不過,像下面這樣為 DOM 元素添加一個自定義的屬性,該屬性不會自動成為元素的特性。

div.mycolor = "red";
alert(div.getAttribute('mycolor'));  //null

要介紹的最后一個方法是removeAttribute(),這個方法用于徹底刪除元素的特性。調(diào)用這個方法不僅會清除特性的值,而且也會從元素中完全刪除特性。

  1. attributes 屬性
    Element類型是使用attributes屬性的唯一一個 DOM 節(jié)點類型。一般不使用。可以用來遍歷節(jié)點的特性。
  2. 創(chuàng)建元素
    使用document.createElement()方法可以創(chuàng)建新元素。這個方法只接受一個參數(shù),即標(biāo)簽名。
var div = document.createElement('div');
div.id = "myNewDiv";
div.className = "box";
document.body.appenChild(div);
  1. 元素的子節(jié)點
    如果需要通過childNodes屬性遍歷子節(jié)點,需要檢查一下nodeType屬性。
for (var i=0, len = element.childNodes.length; i++) {
  if (element.childNodes[i].nodeType == 1) {
    //執(zhí)行某些操作
  }
}

10.1.4 Text 類型

文本節(jié)點由Text類型表示,包含的是可以照字面解釋的純文本內(nèi)容。具有以下特征:

  • nodeType的值為3;
  • nodeName的值為“ #text ”;
  • nodeValue的值為節(jié)點所包含的文本;
  • parentNode是一個Element;
  • 不支持(沒有)子節(jié)點。

使用下列方法可以操作節(jié)點中的文本。

  • appendData(text):將text添加到節(jié)點的末尾。
  • deleteData(offset, count):從offset指定的位置開始刪除count個字符。
  • insertData(offset, text):在offset指定的位置插入text。
  • replaceData(offset, count, text):用text替換從offset指定的位置開始到offset+count為止處的文本。
  • splitText(offset):從offset指定的位置將當(dāng)前文本節(jié)點分成兩個文本節(jié)點。
  • subStringData(offset, count):提取從offset指定的位置開始到offset+count為止的字符串。

文本節(jié)點和還有一個length屬性,保存著節(jié)點中字符的數(shù)目。

  1. 創(chuàng)建文本節(jié)點
    可以使用document.createTextNode()創(chuàng)建文本節(jié)點,這個方法接受一個參數(shù)--要插入節(jié)點中的文本。
var textNode = document.createTextNode("<strong>hello</strong>world!");
var element = document.createElement('div');
element.className = "message";
element.appendChild(textNode);
document.body.appendChild(element);
  1. 規(guī)范化文本節(jié)點
    DOM 文檔中存在相鄰的同胞文本節(jié)點很容易導(dǎo)致混亂,因為分不清哪個文本節(jié)點表示哪個字符串。在一個包含兩個或多個文本節(jié)點的父元素上調(diào)用normalize()方法,則會將所有文本節(jié)點合并成一個節(jié)點,結(jié)果節(jié)點的nodeValue等于將合并前每個文本節(jié)點的nodeValue值拼接起來的值。
  2. 分割文本節(jié)點
    splitText()方法會將一個文本節(jié)點分成兩個文本節(jié)點,即按照指定位置分割nodeValue值。原來的文本節(jié)點將包含從開始到指定位置之前的內(nèi)容,新文本節(jié)點將包含剩下的文本。該方法會返回一個新文本節(jié)點,該節(jié)點與原節(jié)點的parentNode相同。
var element = document.createElement('div');
element.className = 'message';
var textNode = document.createTextNode('hello world!');
element.appendChild(textNode);
document.body.appendChild(element);
var newNode = element.firstChild.splitText(5);
alert(element.firstChild.nodeValue);  //"hello"
alert(newNode.nodeValue);  //"world"
alert(element.childNodes.length);  //2

10.1.5 Comment 類型

注釋在 DOM 中是通過Comment類型來表示的。Comment節(jié)點具有下列特征:

  • nodeType的值為 8;
  • nodeName的值為“ #comment”;
  • nodeValue的值是注釋的內(nèi)容;
  • parentNode可能是DocumentElement;
  • 不支持(沒有)子節(jié)點。

使用document.createComment()并為其傳遞注釋文本也可以創(chuàng)建注釋節(jié)點。
顯然,開發(fā)人員很少會創(chuàng)建和訪問注釋節(jié)點。

10.1.6 CDATASection 類型

CDATASection類型只針對基于 XML 的文檔,表示的是 CDATA 區(qū)域。與Comment類似,CDATASection類型繼承自Text類型,因此擁有除splitText()之外的所有字符串操作方法。
在真正的 XML 文檔中,可以使用document.createCDataSection()來創(chuàng)建 CDATA 區(qū)域,只需為其傳入節(jié)點的內(nèi)容即可。

10.1.7 DocumentType 類型

該類型并不常用。

10.1.8 DocumentFragment 類型

在所有節(jié)點類型中,只有DocumentFragment在文檔中沒有對應(yīng)的標(biāo)記??梢詫⑺鳛橐粋€“倉庫”使用。
如果逐個地添加表項,將會導(dǎo)致瀏覽器反復(fù)渲染(呈現(xiàn))新信息??梢韵裣旅孢@樣使用一個文檔片段來保存創(chuàng)建的列表項,然后再一次性將它們添加到文檔中。

var fragment = document.createDocumentFragment();
var ul = document.getElementById('myList');
var li = null;
for (var i=0; i < 3; i++) {
  li = document.createElement('li');
  li.appendChild(document.createTextNode('item'+(i+1)));
  fragment.appendChild(li);
}
ul.appendChild(fragment);

10.1.9 Attr 類型

元素的特性在 DOM 中以Attr類型來表示。從技術(shù)角度講,特性就是存在于元素的attributes屬性中的節(jié)點。
盡管它們也是節(jié)點,但特性卻不認(rèn)為是 DOM 文檔樹的一部分。最常使用的是getAttribute()、setAttribute()removeAttribute()方法,很少直接引用特性節(jié)點。

10.2 DOM 操作技術(shù)

10.2.1 動態(tài)腳本

創(chuàng)建動態(tài)腳本也有兩種方式:插入外部文件和直接插入 JavaScript 代碼。

var script = document.createElement('script');
script.type = "text/javascript";
script.src = "client.js";
document.body.appendChild(script);

整個過程可以使用下面的函數(shù)來封裝:

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);
}
loadScriptString('function sayHi(){alert('hi');}');

10.2.2 動態(tài)樣式

動態(tài)樣式是在頁面加載完成后動態(tài)添加到頁面中的。

function loadStyles(url) {
  var link = document.createElement('link');
  link.rel = 'stylesheet';
  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);
}
loadStyleString('body{background-color:red}');

10.2.3 操作表格

為了方便構(gòu)建表格,HTML DOM 還為<table>、<tbody><tr>元素添加了一些屬性和方法。

10.2.4 使用 NodeList

理解NodeListNamedNodeMapHTMLCollection,是從整體上透徹理解 DOM 的關(guān)鍵所在。這三個集合都是“動態(tài)的”,每當(dāng)文檔結(jié)構(gòu)發(fā)生變化時,它們都會得到更新。

10.3 小結(jié)

DOM 是語言中立的 API,用于訪問和操作 HTML 和 XML 文檔。 DOM 1 級將 HTML 和 XML 文檔形象地看作一個層次化的節(jié)點樹,可以使用 JavaScript 來操作這個節(jié)點樹,進(jìn)而改變底層文檔的外觀和結(jié)構(gòu)。
DOM 由各種節(jié)點構(gòu)成,簡要總結(jié)如下。

  • 最基本的節(jié)點類型是Node,用于抽象地表示文檔中一個獨立的部分;所有其他類型都繼承自Node。
  • Document類型表示整個文檔,是一組分層節(jié)點的根節(jié)點。在 JavaScript 中, document對象是Document的一個實例。使用document對象,有很多種方式可以查詢和取得節(jié)點。
  • Element節(jié)點表示文檔中的所有 HTML 或 XML 元素,可以用來操作這些元素的內(nèi)容和特性。
  • 另外還有一些節(jié)點類型,分別表示文本內(nèi)容、注釋、文檔類型、CDATA 區(qū)域和文檔片段。

DOM 操作往往是 JavaScript 程序中開銷最大的部分,而因訪問NodeList導(dǎo)致的問題為最多。NodeList對象都是“動態(tài)的”,這就意味著每次訪問NodeList對象,都會運行一次查詢。所以,最好的方法就是盡量減少 DOM 操作。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容