DOM-文档对象模型

DOM是针对HTML和XML文档的一个API(应用程序编程接口)。DOM描绘了一个层次化的节点树,允许开发人员添加、移除和修改页面的某一部分。IE中的所有DOM对象都是COM对象的形式实现的,这意味着IE中的DOM对象与原始JavaScript对象的行为或活动特点并不一致。

节点层次

DOM可以将任何HTML或XML文档描绘成一个由多层结点构成的结构。节点分为几张不同的类型,每种类型分别表示文中的不同的信息及标记。每个结点都拥有各自的特点、数据和方法,另外也与其他结点存在某种关系。结点之间的关系构成了层次,而所有页面标记则表现为一个以特定结点为根节点的树型结构。

Node类型

DOM1级定义了一个Node接口,该接口将由DOM中的所有节点类型实现。每个结点都有一个nodeType属性,用于表明节点的类型。节点类型由在Node类型中定义的下列12个数值常量来表示,任何结点类型必然属于其中的一种:

  • Node.ELEMENT_NODE(1)
  • Node.ATTRIBUTE_NODE(2)
  • Node.TEXT_NODE(3)
  • Node.CDATA_SECTION_NODE(4)
  • Node.ENTITY_PEFERENCE_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)

可以通过节点的nodeType属性判断结点属于哪一种结点。每个结点都有一个childNodes属性,其中保存一个NodeList对象,其为一种类数组对象(并不是Array的实例),用于保存一组有序的节点。可以使用.childNodes[0]或childNodes.item(0)来访问子节点。获取节点可以使用属性:.parentNode .firstChild .lastChild .nextSibling .previousSibling。
操作节点的方法有:

  • .hasChildNodes():判断是否有子节点,有则返回true,没有则返回false
  • .appendChild(newNode):在childNodes列表末尾添加一个新节点,并返回新增的节点。如果插入已存在的结点,则改变节点的位置。
  • .insertBefore(newNode,.old):在相应的节点前添加,如果在新的结点是某个元素的子节点,则该子节点会从该元素中自动去除。
  • .replaceChild(newNode,.old):替换结点
  • removeChild(.old):移除节点。

Document类型

document对象时HTMLDocument的一个实例,表示整个HTML页面。取得特定的某个或某组元素的引用,是常用的DOM应用,Document类型为此提供了两个方法:getElementById()和getElementByTagName()。TagName指标签名称,如div、p、img等。取得元素集合后,使用.nameItem()可以获取相应name的元素。

document对象还提供了一些特殊的集合,包括document.anchors()(包含文档中所有带name属性的<\a>元素)、document.forms()(包含文档中所有的<\form>元素)、document.images()(包含文档中所有的<\img>元素)、document.links()(包含文档中所有带href的<\a>元素)。

document对象有将输入流写入到网页中的能力。有以下四个方法:write()(可以写js代码)、writeln()(在结尾处多一个/n)、open()、close()(打开关闭网页的输出流)。

Element类型

Element类型提供了对元素标签名、子节点及特性的访问,要访问元素的标签名可以用nodeName属性或tagName属性。

所有HTML元素都由HEMLElement类型表示,共有属性为:id、className、title等。操作特性的主要方法有:getAttribute(“title”)、setAttribute(“title”,”test”)、removeAttribute(“title”)。还可以使用.attributes[“id”]等来访问属性。根据HTML5规范,自定义的属性应该加上data-前缀。

可以使用document.createElement(“<\div><\/div>”)方法创建新的元素,并返回新元素,然后通过appendChild()等方法添加到文档树中。

Text类型

文本节点由Text类型表示,包含的是可以照字面解释的纯文本内容。纯文本中可以包含转义后的HTML字符,但不能包含HTML代码。

与element相同,可以通过document.createTextNode()创建新文本节点,并返回新文本节点,然后通过appendChild()等方法添加到文档树中。

使用element.normalize()和element.firstChild.splitText(5)等方法可以合并和分割文本节点。

其他类型

除以上常用类型外,还有Comment类型(注释)、CDATASection类型(显示代码)、DocumentType类型(文档类型声明)、DocumentFragment类型(仓库,可能要添加的节点)、Attr类型(特性节点)

DOM操作技术

动态脚本

使用<\script>元素可以向页面中插入JavaScript代码,一种方式是通过其src特性包含外部文件,另一种方式是通过这个元素本身包含代码。动态创建脚本也有两种:插入外部文件和直接插入JavaScript代码。此时要考虑到兼容性的问题,比如:

1
2
3
4
5
6
7
8
9
10
11
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 asyHi(){alert('hi');}");

动态样式

能够把CSS样式包含到HTML页面中的元素由两个,其中,<\link>元素用于包含来自外部的文件,而<\style>元素用于指定嵌入的样式。

1
2
3
4
5
6
7
8
9
10
11
12
function loadStyleString(css){
var style = document.createElement("style");
style.type = "text/CSS";
try{
style.appendChild(document.createTextNode(css));
}catch(ex){
style.styleSheet.cssText = css;
}
var head = documentl.getElementByTagName("head")[0];
head.appendChild(style);
}
loadStyleString("body{backgroud-color:red}");

使用NodeList

理解NodeList及HTMLCollection和NamedNodeMap,是从整体上透彻理解DOM的关键所在。这单个集合都是“动态的”;每当文档结构发生变化,它们都会更新。从本质上说,所有NodeList对象都是在访问DOM文档时实时运行的查询,所以每次访问NodeList对象,都会进行一次查询。所以要尽量减少DOM操作。可以考虑将从NodeList中取得的值缓存起来,从而减少查询的次数。