欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

DOM1级

程序员文章站 2022-05-06 09:19:43
...

DOM

DOM(文档对象模型)是针对HTML和XML文档的一个API。DOM描绘了一个层次化的节点树,允许开发人员添加、移除和修改页面的某一部分。
DOM可以将任何HTML或XML文档描绘成一个由多层节点构成的结构。节点分为几种不同的类型,每种类型分别表示文档中不同的信息及(或)标记。

在HTML页面中,文档元素始终都是元素。在XML中,没有预定义的元素,因此任何元素都可能成为文档元素。

1 Node类型

DOM1级定义了一个node接口,该接口将由DOM中的所有节点类型实现。这个Node接口在JS中是作为Node类型实现的;除了IE之外,其他所有浏览器都可以访问到这个类型。JS中的所有节点类型都继承自Node类型,因此所有节点类型都共享着相同的基本属性和方法。

每个节点都有一个nodeType属性,用于表明节点的类型。节点类型由在Node类型中定义的下列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);
  • NODEDOCUMENT_NODE(9);
  • NODE.DOCUMENT_TYPE_NODE(10);
  • NODE.DOCUMENT_FRAGMENT_NODE(11);
  • NODE.NOTATION_NODE(12);

为了确保跨浏览器兼容,最好还是将nodeType属性与数字值进行比较,如下所示:

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

1.1 nodeName和nodeValue属性
对于元素节点,nodeName中保存的始终都是元素的标签名,而nodeValue的值则始终未null。

1.2 节点关系
每个节点都有一个childNodes属性,其中保存着一个NodeList对象。NodeList是一种类数组对象,用于保存一组有序的节点,可以通过位置来访问这些节点。请注意,虽然可以通过方括号语法来访问NodeList的值,而且这个对象也有length属性,但它并不是Array的实例。DOM结构的变化能够自动反映在NodeList对象中。

可以通过方括号,也可以使用item()方法。

var firstChild = someNode.childNodes[0];
var secondChild = someNode.item(1);
var count = someNode.childNodes.length;

对arguments对象可以使用Array.prototype.slice()方法可以将其转换为数组。而采用同样地方法,也能将NodeList对象转换为数组。例如:

var arrayOfNodes = Array.prototype.slice.call(NodeList, 0);

为了实现兼容性,可以这样:

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(i);
        }
    }
    return array;
}

每个节点都有一个parentNode属性,该属性指向文档树中的父节点。包含在childNodes列表中的所有节点都具有相同的父节点。因此它们的parentNode属性都指向同一个节点。此外,包含在childNodes列表中的每个节点都是同胞节点。通过使用列表中每个节点的previousSibling和nextSibling属性,可以访问同一列表中的其他节点。

父节点与其第一个和最后一个子节点之间也存在特殊关系。父节点的firstChild和lastChild属性分别指向其childNodes列表中的第一个和最后一个节点。

下图形象地展示了上述关系:

DOM1级

hasChildNodes()也是一个非常有用的方法,这个方法在节点包含一或多个子节点的情况下返回true。

所有节点都有的最后一个属性是ownerDocument,该属性指向表示整个文档的文档节点。

1.3 操作节点

  • appendChild(),用于向childNodes列表的末尾添加一个点。
  • insertBefore(),用于把节点放在childNodes列表中某个特定的位置上,而不是放在末尾。这个方法接受两个参数:要插入的节点和作为参照的节点。如果参照节点是null,则insertBefore()和appendChild()执行相同的操作。
  • replaceChild(),用于替换节点。这个方法接受两个参数,要插入的节点和要替换的节点。要替换的节点将由这个方法返回并从文档树中被移除。同时由要插入的节点占据其位置。
  • removeChild(),用于移除节点。

这四个方法必须先取得父节点(使用parent属性)。在不支持子节点的节点上调用这些方法,将会导致错误发生。

1.4 其他方法

  • cloneNode(),用于创建调用这个方法的节点的一个完全相同的副本。cloneNode()方法接受一个布尔值参数,表示是否执行深复制。在参数为true的情况下,执行深复制,也就是复制节点及其整个子节点树;在参数为false的情况下,执行浅复制,即只复制节点本身。
  • normalize(),用于处理文档树中的文本节点。当在某个节点上调用这个方法时,就会在该节点的后代节点中查找下述两种情况:如果找到了空文本节点,则删除它;如果找到相邻的文本节点,则将它们合并为一个文本节点。

2 Document类型

在浏览器中,document对象是HTMLDocument(继承自Document类型)的一个实例,表示整个HTML页面。而且,document对象是window对象的一个属性,因此可以将其作为全局对象来访问。

其子节点可能是一个DocumentType(最多一个)、Element(最多一个)、ProcessingInstruction或comment。

2.1 文档的子节点
虽然DOM标准规定Document节点的子节点可以是DocumentType、Element、ProcessingInstruction或comment,但还有两个内置的访问其子节点的快捷方式。第一个就是documentElement属性,该属性始终指向HTML页面中的<html>元素。另一个就是通过childNodes列表访问文档元素。例如:

<html>
    <body>

    </body>
</html>

这个页面在经过浏览器解析后,其文档中只包含一个子节点,即<html>元素。可以通过documentElement或childNodes列表来访问这个元素。例如:

var html = document.documentElement;   //取得对&lt;html&gt;的引用
alert(html === document.childNodes[0]);   //true
alert(html === document.firstChild);   //true

作为HTMLDocument的实例,document对象还有一个body属性,直接指向<body>元素。例如:

var body = document.body

2.2 文档信息
作为HTMLDocument的一个实例,document对象还有一些标准的Document对象所没有的属性。

  • document.title,包含着<title>元素中的文本
  • document.URL,包含页面完整的URL
  • document.domain,包含页面的域名,浏览器对domain属性还有一个限制,即如果域名一开始是“松散的”(loose),那么不能将它再设置为“紧绷的”(tight)
  • document.referer,保存着链接到当前页面的那个页面的URL

2.3 查找元素
取得元素的操作可以使用document对象的几个方法来完成。其中,Document类型为此提供了两个方法:
- getElementById(),接收一个参数:要取得的元素的ID
- getElementsByTagName(),接收一个参数:即要取得元素的标签名,而返回的是包含零或多个元素的NodeList。在HTML文档中,这个方法会返回一个HTMLCollection对象,作为一个“动态”集合,该对象与NodeList非常类似。例如:

var images = document.getElementsByTagName("img");
alert(images.length);
alert(images[0].src);
alert(images.item(0).src);

HTMLCollection对象还有一个方法,叫做namedItem(),使用这个方法可以通过元素的name特性取得集合中的项。例如:

<img src="myImage.gif" name="myImage">
var myImage = images.namedItem("myImage");

在提供索引访问项的基础上,HTMLCollection还支持按名称访问项,这就为我们取得实际想要的元素提供了便利。而且,对命名的项也可以使用方括号语法来访问。例如:

var myImage = images["myImage"];

对HTMLCollection而言,我们可以向方括号中传入数值或字符串形式的索引值。在后台,对数值索引就会调用item(),而对字符串索引就会调用namedItem()

第三个方法,也是只有HTMLDocumet类型才有的方法,是getElementsByNames()

2.4 特殊集合
除了属性和方法,document对象还有一些特殊的集合。这些集合都是HTMLCollection对象,为访问文档常用的部分提供了快捷方式。
- document.anchors,包含文档中所有带name特性的<a>元素
- document.forms,包含文档中所有的<form>元素
- document.images,包含文档中所有的<img>元素
- document.links,包含文档中所有带href特性的<a>元素

2.5 文档写入
有一个document对象的功能以及存在很多年了,那就是将输出流写入到网页中的能力。

  • write(),接受一个字符串参数,原样写入
document.write("<strong>" + (new Date()).toString() + "</strong>");
  • writeIn(),和write()基本类似,只不过会在字符串的末尾添加一个换行符(\n)。

如果在文档加载结束后再调用document.write(),那么输出的内容将会重写整个页面。

方法open()和close()分别用于打开和关闭网页的输出流。

3 Element类型

要访问元素的标签名,可以使用nodeName属性,也可以使用tagName属性;这两个属性会返回相同的值(使用后者主要是为了清晰可见)。

3.1 HTML元素
所有HTML元素都由HTMLElement类型表示,不是直接通过这个类型,也是通过它的子类型来表示。HTMLElement类型直接继承自Element并添加了一些属性。添加的这些属性分别对应于每个HTML元素中都存在的下列标准特性。

  • id,元素在文档中的唯一标识符
  • title,有关元素的附加说明信息,一般通过工具提示条显示出来
  • lang,元素内容的语言代码,很少使用
  • dir,语言的方向,值为“ltr”(left to right,从左至右)或“rtl”(right to left,从右至左),也很少使用
  • className,与元素的class特性对应,即为元素指定的CSS类。没有将这个属性命名为class,是因为class是ES的保留字。

3.2 取得特性、设置特性和移除特性
操作特性的DOM方法主要有三个,分别是getAttribute(),setAttribute(),removeAttribute()。

通过getAttribute()方法也可以取得自定义特性(即标准HTML中语言中没有的特性)的值,以下面的元素为例:

<div id="myDiv" my_special_attribute="hello!"></div>
var value = div.getAttribute("my_special_attribute");

根据HTML5规范,自定义特性应该加上data-前缀以便验证。

只有在取得自定义特性值的情况下,才会使用getAttribute()方法

3.3 attributes属性
Element类型是使用attributes属性的唯一一个DOM节点类型。attributes属性中包含一个NamedNodeMap,与NodeList类似,也是一个动态的集合。元素的每一个特性都由一个Attr节点表示,每个节点都保存在NamedNodeMap对象中。NamedNodeMap对象拥有下列方法:

  • getNamedItem(name):返回NodeName属性等于name的节点
  • removeNamedItem(name):从列表中移除nodeName属性等于name的节点
  • setNamedItem(node):向列表中添加节点,以节点的nodeName属性为索引
  • item(pos):返回位于数字pos位置处的节点
var div1 = document.getElementById("div1");
var type = document.createAttribute("class");
type.nodeValue = "class1";
div1.attributes.setNamedItem(type);

以上是setNamedItem()的方法。

一般来说,attributes的方法不够方便,更多会使用getAttribute()、removeAttribute()、setAttribute()方法。

不过,如果想要遍历元素的属性,attributes属性倒是可以派上用场。例如:

var div1 = document.getElementById("div1");
function outputAttributes(element) {
    var pairs = new Array(), 
    attrName,
    attrValue,
    i,
    len;

for(i = 0, len = element.attributes.length; i < len; i++) {
    attrName = element.attributes[i].nodeName;
    attrValue = element.attributes[i].nodeValue;
    if(element.attributes[i].specified) {
        pairs.push(attrName + "=\"" + attrValue + "\"");
        }
    }
    return pairs.join(" ");
}

alert(outputAttributes(div1));   //'id="div1" class="div2"'

3.4 创建元素
使用document.createElement()方法可以创建新元素。这个方法只接受一个参数,即要创建元素的标签名。

3.5 元素的子节点
元素可以有任意数目的子节点和后代节点,因为元素可以是其他元素的子节点。元素的hildNodes属性中包含了它的所有子节点,这些子节点有可能是元素、文本节点、注释或处理指令。例如:

<ul id="myList">
    <li>Item1</li>
    <li>Item2</li>
    <li>Item3</li>
</ul>

如果是IE来解析这段代码,那么<ul>会有三个子节点,分别是3个<li>元素。但如果是在其他浏览器中,<ul>元素都会有七个元素,包括三个<li>元素和四个文本节点。如果像下面这样将元素间的空白符删除,那么所有浏览器都会返回相同数目的子节点。

<ul id="myList"><li>Item1</li><li>Item2</li><li>Item3</li></ul>

4 文本类型

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

可以通过nodeValue属性或data属性访问Text节点中包含的文本,这两个属性中包含的值相同。

可以通过下列方法操作节点中的文本:

  • appendData(text):将text添加到节点的末尾。
  • deleteData(offset, count):从offset指定的位置开始删除count个字符。
  • insertData(offset, text):在offset指定的位置插入text。
  • replaceData(offset, count, text):用text替换从offset指定的位置开始到offset+count为止处的文本。
  • splitData(offset):从offset指定的位置将当前文本, 节点分成两个文本节点。
  • substringData(offset, count):提取从offset指定的位置开始到offset+count为止处的字符串。

文本节点还有一个length属性,保存着节点中字符的数目。而且,nodeValue.length和data.length中也保存着同样的值。

在默认情况下,每个可以包含内容的元素最多只能有一个文本节点,而且必须确实有内容存在。

4.1 创建文本节点
可以使用document.createTextNode()创建新文本节点,这个方法接受一个参数——要插入节点中的文本。

4.2 规范化文本节点
如果在一个包含两个或多个文本节点的父元素上调用normalize()方法,则会将所有文本节点合并成一个节点,结果节点的nodeValue等于将合并前每个文本节点的nodeValue值拼接起来的值。

4.3 分割文本节点
Text类型提供了一个作用与normalize()相反的方法:splitText()。这个方法将一个文本节点分成两个文本节点,即按照指定的位置分割nodeValue值。原来的文本节点将包含从开始到指定位置之前的内容,新文本节点将包含剩下的文本。

5 Comment类型

Comment类型与Text类型继承自相同的基类,因此它拥有除splitText()之外的所有字符串操作方法。与Text类型相似,也可以通过nodeValue或data属性来取得注释的内容。

可以使用document.createComment()并为其传递注释文本创建注释节点

6 DocumentType类型

DocumentType包含着与文档的doctype有关的所有信息。
在DOM1级中,DocumentType对象不能动态创建,而只能通过解析文档代码的方式来创建。支持它的浏览器会把DocumentType对象保存在document.doctype中。DOM1级描述了DocumentType对象的三个属性:name、entities和notations。其中,name属性表示文档类型的名称;entities是由文档类型描述的实体的NamedNodeMap对象;notations是由文档类型描述的符号的NamedNodeMap对象;只有name属性是有用的。这个属性保存的是文档类型的名称,也就是出现在<DOCTYPE之后的文本。

7 DocumentFragment类型

在所有节点类型中,只有DocumentFragment在文档中没有对应的标记。DOM规定文档片段(document fragment)是一种“轻量级”的文档,可以包含和控制节点,但不会像完整的文档那样占用额外的资源。

虽然不能把文档片段直接添加到文档中,但可以将它作为一个“仓库”来使用,即可以在里面保存将来可能会添加到文档中的节点。要创建文档片段,可以使用document.createDocumentFragment()方法,如下所示:

var fragment = document.createDocumentFragment();

如果将文档中的节点添加到文档片段中,就会从文档树中移除该节点,也不会从浏览器中再看到该节点。添加到文档片段中的新节点同样也不属于文档树。可以通过appendChild()或insertBefore()将文档片段中内容添加到文档中。在将文档片段作为参数传递给这两个方法时,实际上只会将文档片段的所有子节点添加到相应位置上;文档片段本身永远不会成为文档树中的一部分。例如:

<ul id="myList"></ul>

假设我们想为这个<ul>元素添加3个列表项。如果逐个地添加列表项,将会导致浏览器反复渲染(呈现)新信息。为避免这个问题,可以使用一个文档片段来保存创建的列表项,然后再一次性将它们添加到文档中。

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

8 Attr类型

元素的特性在DOM中以Attr类型来表示。

Attr对象有三个属性:name、value和specified。其中,name是特性名称(与nodeName的值相同),value是特性的值(与nodeValue的值相同),而specified是一个布尔值,用以区别特性是在代码中指定的,还是默认的。

使用document.createAttribute()并传入特性的名称可以创建新的特性节点。例如:

var attr = document.createAttribute("align");
attr.value = "left";
element.setAttributeNode(attr);
alert(element.attributes["align"].value);   //"left"
alert(element.getAttributeNode("align").value);   //"left"
alert(element.getAttribute("align"));   //"left"

9 DOM操作技术

9.1 动态脚本
跟操作HTML元素一样,创建动态脚本也有两种方式:插入外部文件和直接插入Javascript代码。

9.2 动态样式
与动态脚本类似,所谓动态样式是指在页面加载时不存在的样式;动态样式是在页面加载完成后动态添加到页面中的。

9.3 操作表格

9.4 使用nodeList

相关标签: DOM