3.7 DOM技术

视频讲解:光盘\TM\lx\3\13 DOM技术.mp4

DOM是Document Object Model(文档对象模型)的简称,是表示文档(如HTML文档)和访问、操作构成文档的各种元素(如HTML标记和文本串)的应用程序接口(API)。它提供了文档中独立元素的结构化、面向对象的表示方法,并允许通过对象的属性和方法访问这些对象。另外,文档对象模型还提供了添加和删除文档对象的方法,这样能够创建动态的文档内容。DOM也提供了处理事件的接口,它允许捕获和响应用户以及浏览器的动作。下面将对其进行详细介绍。

3.7.1 DOM的分层结构

在DOM中,文档的层次结构以树形表示。树是倒立的,树根在上,枝叶在下,树的节点表示文档中的内容。DOM树的根节点是个Document对象,该对象的documentElement属性引用表示文档根元素的Element对象。对于HTML文档,表示文档根元素的Element对象是<html>标记,<head>和<body>元素是树的枝干。

【例3.40】一个简单的HTML文档说明DOM的分层结构。代码如下:

        <html>
            <head>
                <title>一个HTML文档</title>
            </head>
            <body>
                欢迎访问明日科技网站!
                <br>
                <a href="http://www.mingribook.com"> http://www.mingribook.com</a>
            </body>
        </html>

上面的HTML文档的运行结果如图3.22所示,对应的Document对象的层次结构如图3.23所示。

图3.22 HTML文档的运行结果

图3.23 Document对象的层次结构

说明

在树形结构中,直接位于一个节点之下的节点称为该节点的子节点(children);直接位于一个节点之上的节点称为该节点的父节点(parent);位于同一层次,具有相同父节点的节点是兄弟节点(sibling);一个节点的下一个层次的节点集合是该节点的后代(descendant);一个节点的父节点、祖父节点及其他所有位于它之上的节点都是该节点的祖先(ancestor)。

3.7.2 遍历文档

在DOM中,HTML文档中的各个节点被视为各种类型的Node对象,并且将HTML文档表示为Node对象的树。对于任何一个树形结构来说,最常做的就是遍历树。在DOM中,可以通过Node对象的parentNode、firstChild、nextChild、lastChild、previousSibling等属性来遍历文档树。Node对象的常用属性如表3.14所示。

表3.14 Node对象的常用属性

由于HTML文档的复杂性,DOM定义了nodeType来表示节点的类型。下面以列表的形式给出Node对象的节点类型、节点名、节点值及节点类型常量,如表3.15所示。

表3.15 Node对象的节点类型、节点名、节点值及节点类型常量

【例3.41】遍历JSP文档,获取该文档中的全部标记及标记总数。(实例位置:光盘\TM\sl\3\11)

(1)编写index.jsp文件,在该文件中添加提示性文字及进入明日科技网站的超链接。具体代码如下:

        <%@ page language="java" pageEncoding="GBK"%>
        <html>
            <head>
                <title>一个简单的文档</title>
            </head>
            <body>
                欢迎访问明日科技网站!
                <br>
                <a href="http://www.mingribook.com"> http://www.mingribook.com</a>
          </body>
        </html>

(2)编写JavaScript代码,用于获取文档中全部的标记,并统计标记的个数。具体代码如下:

        <script language="javascript">
            var elementList="";                         //全局变量,保存Element标记名,使用之后要清空
            function getElement(node){                                        //参数node是一个Node对象
                var total = 0;
                if(node.nodeType==1){                                         //检查node是否为Element对象
                    total++;                                                  //如果是,计数器加1
                    elementList=elementList+node.nodeName+"、";               //保存标记名
                }
                var childrens=node.childNodes;                                //获取node的全部子节点
                for(var m=node.firstChild; m! =null; m=m.nextSibling) {
                    total+=getElement(m);                                     //对每个子节点进行递归操作
                }
                return total;
            }
            function show(){
                var number=getElement(document);                              //获取标记总数
                elementList=elementList.substring(0, elementList.length-1);   //去除字符串中最后一个逗号
                alert("该文档中包含:"+elementList+"等"+number+"个标记!");
                elementList="";                                               //清空全局变量
            }
        </script>

(3)在页面的onload事件中,调用show()方法获取并显示文档中的标记及标记总数。具体代码如下:

        <body onload="show()">

运行程序,将显示如图3.24所示的页面,并弹出提示对话框显示文档中的标记及标记总数。

图3.24 实例运行结果

3.7.3 获取文档中的指定元素

虽然通过3.7.2节中介绍的遍历文档树中全部节点的方法可以找到文档中指定的元素,但是这种方法比较麻烦。下面介绍两种直接搜索文档中指定元素的方法。

1.通过元素的id属性获取元素

使用Document对象的getElementsById()方法可以通过元素的id属性获取元素。例如,获取文档中id属性为userList的节点。代码如下:

        document.getElementById("userList");

2.通过元素的name属性获取元素

使用Document对象的getElementsByName()方法可以通过元素的name属性获取元素。与getElementsById()方法不同的是,该方法的返回值为一个数组,而不是一个元素。如果想通过name属性获取页面中唯一的元素,可以通过获取返回数组中下标值为0的元素进行获取。例如,获取name属性为userName的节点。代码如下:

        document.getElementsByName("userName")[0];

3.7.4 操作文档

在DOM中不仅可以通过节点的属性查询节点,还可以对节点进行创建、插入、删除和替换等操作。这些操作都可以通过节点(Node)对象提供的方法来完成。Node对象的常用方法如表3.16所示。

表3.16 Node对象的常用方法

【例3.42】应用DOM操作文档,实现添加评论和删除评论的功能。(实例位置:光盘\TM\sl\3\12)

(1)在页面的合适位置添加一个1行2列的表格,用于显示评论列表,并将该表格的ID属性设置为comment。具体代码如下:

        <table width="600" border="1" align="center" cellpadding="0" cellspacing="0" bordercolor="#FFFFFF"
        bordercolorlight="#666666" bordercolordark="#FFFFFF" id="comment">
          <tr>
            <td width="18%" height="27" align="center" bgcolor="#E5BB93">评论人</td>
            <td width="82%" align="center" bgcolor="#E5BB93">评论内容</td>
          </tr>
        </table>

(2)在评论列表的下方添加一个用于收集评论信息的表单及表单元素。具体代码如下:

        <form name="form1" method="post" action="">
        评论人:<input name="person" type="text" id="person" size="40">
        评论内容:<textarea name="content" cols="60" rows="6" id="content"></textarea>
        </form>

(3)编写自定义JavaScript函数addElement(),用于在评论列表中添加一条评论信息。在该函数中,首先将评论信息添加到评论列表的后面,然后清空评论人和评论内容文本框。具体代码如下:

        function addElement() {
            var person=document.createTextNode(form1.person.value);   //创建代表评论人的TextNode节点
            var content=document.createTextNode(form1.content.value); //创建代表评论内容的TextNode节点
            //创建td类型的Element节点
            var td_person = document.createElement("td");
            var td_content = document.createElement("td");
            var tr=document.createElement("tr");                      //创建一个tr类型的Element节点
            var tbody=document.createElement("tbody");                //创建一个tbody类型的Element节点
            //将TextNode节点加入到td类型的节点中
            td_person.appendChild(person);                            //添加评论人
            td_content.appendChild(content);                          //添加评论内容
            //将td类型的节点添加到tr节点中
            tr.appendChild(td_person);
            tr.appendChild(td_content);
            tbody.appendChild(tr);                                    //将tr节点加入tbody中
            var tComment=document.getElementById("comment");          //获取table对象
            tComment.appendChild(tbody);                              //将节点tbody加入节点尾部
            form1.person.value="";                                    //清空评论人文本框
            form1.content.value="";                                   //清空评论内容文本框
        }

(4)编写自定义JavaScript函数deleteFirstE(),用于将评论列表中的第一条评论信息删除。deleteFirstE()函数的具体代码如下:

        function deleteFirstE(){
            var tComment=document.getElementById("comment");     //获取table对象
            if(tComment.rows.length>1){
                tComment.deleteRow(1);                           //删除表格的第二行,即第一条评论
            }
        }

(5)编写自定义JavaScript函数deleteLastE(),用于将评论列表中的最后一条评论信息删除。deleteLastE()函数的具体代码如下:

        function deleteLastE(){
            var tComment=document.getElementById("comment");     //获取table对象
            if(tComment.rows.length>1){
                tComment.deleteRow(tComment.rows.length-1);      //删除表格的最后一行,即最后一条评论
            }
        }

(6)分别添加“发表”按钮、“删除第一条评论”按钮和“删除最后一条评论”按钮,并在各按钮的onclick事件中,调用发表评论函数addElement()、删除第一条评论函数deleteFirstE()和删除最后一条评论函数deleteLastE()。另外,还需要添加“重置”按钮。具体代码如下:

        <input name="Button" type="button" class="btn_grey" value="发表" onClick="addElement()">
        <input name="Reset" type="reset" class="btn_grey" value="重置">
        <input name="Button" type="button" class="btn_grey" value="删除第一条评论" onclick="deleteFirstE()">
        <input name="Button" type="button" class="btn_grey" value="删除最后一条评论" onclick="deleteLastE()">

运行程序,在“评论人”文本框中输入评论人,在“评论内容”文本框中输入评论内容,单击“发表”按钮,即可将该评论显示到评论列表中;单击“删除第一条评论”按钮,将删除第一条评论;单击“删除最后一条评论”按钮,将删除最后一条评论,如图3.25所示。

图3.25 添加和删除评论