本文和大家重点讨论一下DOM模型的概念和用法,DOM的全称是DocumentObjetModule即文档对象模型,在Web上把页面的HTML表现看作一个有树型结构的对象模型,可以通过一些操作接口来对Document的每一个子对象节点进行访问和操作,这就为Ajax在不刷新页面的情况下改变页面显示数据成为了可能。
DOM模型基础
DOM的全称是DocumentObjetModule即文档对象模型,在Web上把页面的HTML表现看作一个有树型结构的对象模型,可以通过一些操作接口来对Document的每一个子对象节点进行访问和操作,这就为Ajax在不刷新页面的情况下改变页面显示数据成为了可能。
先来看一个简单的HTML片段:
- <htmlxmlnshtmlxmlns="http://www.w3.org/1999/xhtml">
- <head><title>DOM模型</title></head><body>
- <labeltitlelabeltitle="title1">DOM模型节点</label></body></html>
在这个HTML页面中,只有一个Label控件,可以根据节点的层次画出这个页面的层次结构图。
通常来说,在HTML文档中的每一个标签都表示一个对象节点。而像上面<Lable>这样的标签是我们的HTML元素节点,而标签中的title=“title1”是一个属性节点,而“DOM模型节点”这样的文本构成了一个文本节点。
那么,怎么才能对DOM模型中的一个节点进行操作呢,首先要做的是对这个节点进行引用。
1.对文档节点的引用
下面列举一些常用的对文档元素节点的引用方法。
◆document.GetElementById()方法直接引用节点,这个是我们在实际应用中最常用的一种方法,在HTML文档中每一个元素节点都可以定义一个唯一的id属性,然后使用GetElementById方法就可以准确地得到对这个节点的引用。
- <htmlxmlnshtmlxmlns="http://www.w3.org/1999/xhtml">
- <head><title>DOM模型</title></head><body><dividdivid="Div1">
- <labeltitlelabeltitle="title1">Dom模型节点</label></div></body>
- </html><scriptlanguagescriptlanguage="javascript"type="text/javascript">
- <!--var_div1=document.getElementById("Div1");
- alert(_div1.innerHTML);//弹出警告框显示了标签div中的HTML内容
- //<labeltitlelabeltitle="title1">Dom模型节点</label>--></script>
HTML文档中每一个元素节点都有innerHTML这个属性,我们通过对这个属性的访问可以获取或者设置这个元素节点标签内的HTML内容,自IE4.0以来越来越多的浏览器支持了这一属性,通过使用这一属性使许多繁杂的动态生成HTML的工作变得简单。需要注意的是,我们如果对单标记标签,如<img>这一类标签的innerHTML属性读取会得到一个空字符串,而写将会得到一个错误。
此外document对象还有一个类似的方法GetElementByName,我们可以通过form标签的name属性对表单元素节点进行引用,但返回的通常是一个数组,因为表单中的节点name属性的值不是唯一的,可以通过索引器得到每一个元素的引用。
◆document.getElementByTagName()
可以得到一个指定标记名称节点引用的数组集合,可以通过索引器对每个节点的引用进行访问。
- <htmlxmlnshtmlxmlns="http://www.w3.org/1999/xhtml"><head>
- <title>DOM模型</title></head><body>
- <dividdivid="Div1">节点1</div><dividdivid="Div2">节点2</div>
- </body></html><scriptlanguagescriptlanguage="javascript"
- type="text/javascript">
- <!--var_divs=document.getElementsByTagName("div");
- for(vari=0;i<_divs.length;i++)alert(_divs[i].innerHTML);
- //依次显示了"节点1"和"节点2"--></script>
这个方法通常在要对整个文档的某一类元素节点进行操作时用到,比如说为全部的图片添加一个鼠标掠过时发生位移的效果,这时就可以通过这个方法对文档所有的节点进行引用。
◆parentNode和childNodes,可以通过访问这两个属性获得当前节点的父节点和子节点集合的引用。
- <htmlxmlnshtmlxmlns="http://www.w3.org/1999/xhtml">
- <head><title>DOM模型</title></head>
- <body><dividdivid="Div1"><spanidspanid="sp1">节点1</span>
- <spanidspanid="sp2">节点2</span></div></body></html>
- <scriptlanguagescriptlanguage="javascript"type="text/javascript">
- <!--var_nod=document.getElementById("sp1");
- //得到对sp1的引用var_pNod=_nod.parentNode;
- //得到对Div1的引用alert(_pNod.innerHTML);
- //显示父节点内容for(vari=0;i<_pNod.childNodes.length;i++)
- //循环子节点alert(_pNod.childNodes[i].innerHTML);
- //依次显示了每一个节点的内容--></script>
在这里问题出现了,我们发现在IE和FF下面对属性_pNod.childNodes.length,即子节点的数量解释不同,在IE中为4,而在FF中为5。得到这样的结果是因为两种浏览器对文档中换行产生的文本节点的解释不统一造成的,IE没有把父节点与子节点之间那个换行作为一个文本节点,如果要使用这个属性就不得不在HTML文档编写的时候避免出现换行,可以将上面的结构改为下面的形式:
- <dividdivid="Div1">
- <spanidspanid="sp1">节点1</span>
- <spanidspanid="sp2">节点2</span></div>
虽然这样写以后FF和IE都能很好地统一解释为两个子节点,但是损失了文档的美观性和易读性,所以一般都不推荐使用访问子节点的方法来引用节点。
类似的previousSibling和nextSibling也存在类似的问题。这两个属性是用来引用上一个或者下一个兄弟节点的,使用这两个属性时也存在空白文本节点的问题,我们也应该尽量避免使用这两个属性。#p#
2.文档元素节点的操作
得到一个文档元素节点的引用之后,就可以对这个节点进行一些控制和操作,以达到对HTML显示进行更新的目的。
(1)DOM标准操作,在DOM模型中定义了一套能够对文档结构进行更新的方法,我们可以通过这些方法创建文档节点,并将节点添加到文档中或者从文档中删除。
◆document.createElement(elmName)根据标记名称创建一个节点。
◆document.createTextNode(text)根据一段文本创建一个文本节点。
◆node.appendChild(childNode)将节点添加到一个节点下子节点的末尾。
◆node.insertBefor(newNode,oldNode)将节点插入到指定节点之前,newNode为新节点,oldNode为指定的节点,此节点必须为node的已经存在的一个子节点。
◆node.Replace(newNode,oldNode)用新节点取代一个旧节点,与上面方法类似,oldNode必须为node的一个已近存在的子节点。
◆node.cloneNode(cloneChild)复制一个节点,参数cloneChild是一个布尔值,表示是否复制子节点。
◆node.removeChild(childNode)删除一个子节点,需要注意的是该方法将返回被删除节点的引用。
下面我们用一个例子来说明这些方法的使用:
- var_div1=document.getElementById("div1");
- //获取Div1节点var_sp3=document.createElement("span");
- //创建一个<span>元素节点_sp3.id="span3";
- //将新节点的属性id设为"span3"var_txt1=document.createTextNode("节点3");
- //创建一个文本节点_sp3.appendChild(_txt1);
- //将文本节点添加到新元素节点下_div1.appendChild(_sp3);
- //将元素节点添加到节点Div1下
- //此时界面显示节点1节点2节点3var_sp4=_sp3.cloneNode(true);
- //将元素节点复制_sp4.id="span4";
- //为新复制的节点设置id属性var_txt2=document.createTextNode("节点4");
- //新建一个文本节点_sp4.replaceChild(_txt2,_sp4.childNodes[0]);
- //将节点_sp4的文本节点替换_sp3.parentNode.insertBefore(_sp4,_sp3);
- //将节点_sp4添加到节点_sp3之前
- //此时界面显示节点1节点2节点4节点3_sp4.parentNode.removeChild(_sp4);
- //删除节点_sp4
(2)Table的操作
我们发现如果通过以上的方法对表格对象<table>进行操作的话,在IE下将得不到正确的结果,在IE下必须使用DOM1的方法对表格进行操作。
◆tab.insertRow(idx)在表格指定索引位置添加一行空行,idx为索引位置。
◆tab.deleteRow(idx)在表格指定索引位置删除一行。
◆row.insertCell(idx)在行的指定索引位置添加一个空单元格。
◆row.deleteCell(idx)在行的指定位置删除一个单元格。
可以通过document.createElement(“table”)创建一个表格,通过索引器可以访问talbe的各个行和单元格,如tab.rows[1].cells[3],这样我们就能得到表格的第二行第四列的引用,我们可以向操作普通节点一样来对这个单元格对象进行操作。下面是一个表格操作的例子,假定这个表格原来有2行2列。
- vartab=document.getElementById("tab");
- //得到对表格的引用varrow2=tab.insertRow(2);
- //新增第三行varcell20=row2.insertCell(0);
- //为第三行添加第一个单元格cell20.innerHTML="20";
- //varcell21=row2.insertCell(1);//为第三行添加第二个单元格cell21.innerHTML="21";
- tab.rows[1].deleteCell(1);//删除第二行第二列tab.deleteRow(1);
- //删除第二行
(3)innerHTML的灵活使用
在IE4.0以后,elm.innerHTML这个属性得到大部分浏览器的广泛支持,其易用性使得我们对文档的操作得到了很大程度的简化,下面来看一个操作文档节点的例子,假设要对一个节点添加两个子节点,并设置一些属性,下面是DOM模型标准创建方法:
- var_div1=document.getElementById("div1");
- //得到父节点var_sp1=document.createElement("span");
- //创建span节点_sp1.id="span1";
- var_txt1=document.createTextNode("节点1");
- //创建文本节点_sp1.appendChild(_txt1);
- //将文本加入到span节点下_div1.appendChild(_sp1);
- //将span节点加入到父节点下
这样写我们通过六行代码完成了功能的实现,下面来看使用innerHTML的情况
- var_div2=document.getElementById("div2");
- _div2.innerHTML="<spanid='span1'>节点2</span>";
运行后发现,只使用了两行代码而得到了完全相同的效果,并且这种方法还更为直观一些,可读性还更强。可见使用innerHTML属性,可以更为方便高效地改变文档结构,这使得在大多数情况下都使用innerHTML来操作文档,但是标准的DOM模型方法在特定的环境下也有不可取代的作用,在编码时要灵活判断,选择合适的方法解决问题。
【编辑推荐】
- JavaScript DOM特性与应用详解
- HTML DOM入门级知识手册
- HTML DOM display属性语法实例解析
- 深入了解JavaScript HTML DOM对象
- 术语汇编 Javascript DOM技术探究