ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

第9章 DOM

2022-05-14 10:33:28  阅读:107  来源: 互联网

标签:Level 对象 标签 DOM HTML 节点


绩效

章节 代码量(行)
9.1 2
9.2 22
9.3

9.1 DOM的定义

在希望通过 JavaScript 来对页面的内容进行操作时,如果文档的内容与结构能够以一种便于程序处理的形式表现,无疑会给处理带来方便。比如说,虽然可以直接修改以字符串形式表示的 HTML 资源内容,但如果可以对“id 是 foo 的 <div> 标签”,或“所有的<a> 标签”这样的集合进行操作,则程序的可读性会更高,书写也较为简单。为此,JavaScript 中引入了DOM 的概念。

DOM 是一种 API,其作用为在程序中使用 HTML文档以及 XML 文档。在 DOM 中,HTML 文档与XML 文档会以树形对象集合的形式被使用。这一树形结构称为 DOM 树。

DOM 树中的一个个对象被称为节点。节点之间形成了一个树形结构,树中的某个节点可能会引用另外一个节点。根据引用关系,分别有父节点、子节点、兄弟节点、祖先节点、子孙节点等类型。

根据 W3C 的定义,DOM 可以分为 Level1 ~ 3这几层。

9.1.1 DOM Level 1

DOM Level 1 是由 Core 与 HTML 这两个模块组成的(表 9.1)。在 DOM Level 1 Core 中包含很多操作 DOM 树的方法。表 9.2 介绍了 DOM Level 1 Core 中定义的一些基本方法,更为详细的内容会在之后进一步说明。

表 9.1 DOM Level 1 的模块一览
模块 说明
Core 对包括HTML 在内的基本DOM 操作提供支持
HTML 对一些专用于HTML 文档的方法提供支持
表 9.2 DOM Level 1 Core
方法名 说明
getElementsByTagName 根据指定的标签名来获取元素
createElement 创建新元素
appendChild 插入元素

9.1.2 DOM Level 2

与 DOM Level 1 相比,DOM Level 2 中包含了很多模块。其中包括 Events 这样与addEventListener()等事件处理方法相关的模块,或者 DOM Level 1 中 Core 模块以及 HTML 模块的扩展模块。

CSS 也是在 DOM Level 2 中定义的模块。可惜的是,Internet Explorer 8 以及更早的版本并没有遵循DOM Level 2 标准。而 Firefox 或 Google Chrome 等现代浏览器则几乎完全支持 DOM Level 2。

表 9.3 DOM Level 2 所包含的模块一览
模块 说明
Core Level 1 Core 的扩展
HTML Level 1 HTML 的扩展
Views 对与文档显示状态相关的功能提供支持
Events 对捕获、冒泡、取消等事件系统提供支持
Styles 对与样式表相关的功能提供支持
Traversal and Range 对DOM 树的遍历以及范围的指定提供支持

9.1.3 DOM Level 3

DOM Level 3 是由表 9.4 中所示的模块所组成的,其中 Events 模块还没有达到推荐使用的程度。不过在现代浏览器中,Event 模块中所定义的一些内容已经提前实现。

表 9.4 DOM Level 3 所包含的模块一览

模块 说明
Core Level 2 Core 的扩展
Load and Save 对文档内容的读取与写入提供支持
Validation 对文档内容合法性的验证提供支持
XPath 对XPath 相关的功能提供支持
Events Level 2 Events 的扩展。对键盘事件提供了支持
专栏
DOM Level 0

在 DOM 标准制定之前,各种浏览器所采用的对象模型被称为 DOM Level 0。DOM Level 0 也称为传统 DOM。虽然 DOM Level 0 并不能算是一种被正确定义的标准,但为了与过去的浏览器相兼容,现在的浏览器中仍然支持 DOM Level 0 中的功能。DOM Level 0 中含有 Window、Document、Navigator、Location、History 等对象。不过,在 Document 对象中也有一些在 DOM Level 1 中被定义的 API,所以不能说以上这些对象都是属于DOM Level 0 的内容。

此外,虽然 DOM Level 0 并不能算是一种标准,但是它所包含的一些对象却是符合 HTML5 标准的。很多过去由浏览器开发商自主实现的功能现在也都成为了标准。还有一些功能虽然还没有成为标准,但也已经处于标准起草阶段了。这些由浏览器开发商自主实现的功能为了不与 DOM 标准中所定义的属性名或名称冲突,常常会根据开发商的不同分别在名称前加上前缀。其中的很多被用于 CSS 的属性或 JavaScript 的函数名中。例如,在 Firefox中使用了 moz 这一前缀,而在 Google Chrome 与 Safari 所使用的 WebKit 中则使用了 webkit 这一前缀。

9.1.4 DOM 的表述方式

可以通过下面的方式书写 DOM。

接口名·方法名()
接口名·属性名

虽然这种写法会使 DOM 的书写变得冗长,但以这样的方式书写 JavaScript 代码就可以清楚地知道正在对哪一个接口的对象进行操作,将有助于增进对代码的理解。所以还是应采用这种方法。同时,在方法名之后接上 () 之后,就能够清楚地知道该元素是一个方法。

9.2 DOM的基础

9.2.1 标签、元素、节点

在对 HTML 以及 DOM 进行讨论时,我们常常会混用标签、元素、节点等术语。故在此再次对它们的定义进行确认。

标签

标签是一种用于标记的字符串,其作用为对文档的结构进行指定。通常都会有起始标签与结束标签。在结束标签中,有一些可以被省略,如 <p> 标签。同时也有一些标签不存在结束标签,例如 <input> 标签(代码清单 9.1)。说到底标签只是用于书写场合,在谈论 DOM 的话题时几乎不会使用。

代码清单 9.1 标签
<div> <!-- div的起始标签 -->
    <p> <!-- p的结束标签可以省略 -->
        <input type="button"> <!-- input只有起始标签而没有结束标签 -->
</div> <!-- div的结束标签 -->
元素、节点

比较容易产生混淆的是元素和节点的概念。元素和节点之间略有一些继承关系,其中节点是父类概念。节点具有 nodeType 这一属性,如果其值为 ELEMENT_NODE(1),该节点则是一个元素。

表 9.5 总结了 HTML 文档常用的节点。

表 9.5 在 HTML 文档中使用的节点
节点 节点类型常量 节点类型的值 接口
元素节点 ELEMENT_NODE 1 Element
属性节点 ATTRIBUTE_NODE 2 Attr
文本节点 TEXT_NODE 3 Text
注释节点 COMMENT_NODE 8 Comment
文档节点 DOCUMENT_NODE 9 Document

9.2.2 DOM 操作

JavaScript 的作用是使网页能够执行某些功能。为了实现这些功能,必须对 DOM 进行操作。通过选择某个 DOM 元素并改写其属性,或创建一个新的 DOM 元素,就能够给予用户视觉反馈,以实现交互功能。之后,将从选择、创建、更改 与 删除 四个方面对 DOM 的相关操作进行说明。

9.2.3 Document 对象

Document 对象是 DOM 树结构中的根节点。虽然这是一个根节点,在 HTML 文档中却不用书写其对应的标签。例如,虽然 <html> 标签与 <body> 标签分别对应 Document 对象中的 documentElement 属性与 body 属性,但却没有与Document 对象自身相对应的标签。这是因为 Document 对象是一种用于表示整个 HTML 文档的对象。

可以通过 JavaScript 中的 document 这一全局变量来访问 Document 对象。准确地说,document 是 window 对象中的一个属性。不过,由于 window 对象是一个全局对象,因此在对其属性进行访问时可以将 window. 省略不写。

实际上,在通过 JavaScript 表示 HTML 文档时,所有的全局变量都是 window 对象的属性。可以通过下面的代码对此进行确认。

<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>测试</title>
</head>

<body>
    <script>
        var hzh = '黄子涵';
        alert(window.hzh === '黄子涵');
    </script>
</body>

</html>

image

顺便提一下,window 对象并没有包含于 DOM 树结构之中。如前面所讲,Document 对象在 DOM 树结构中是根节点,因此也无法通过下面将要介绍的方法来取得 Document 对象的父节点。

9.3 节点的选择

9.3.1 通过 ID 检索

在 JavaScript 中,如果要对 HTML 文档中的指定节点进行选择,Document.getElementById() 方法是一种最为常见的手段。该方法可以像下面这样书写。

var element = document.getElementById('hzh');

这样就能够取得 ID 为 hzh 的元素。ID 在 DOM树中必须是唯一的。在 DOM 中并没有对存在多个相同 ID 的情况做出规定。不过,大部分的浏览器都采用了返回第一个找到的元素的方式。

不过即便如此,也不应该根据这一规则来进行设计。这样的做法是错误的,ID 必须是唯一的(代码清单9.2)。

代码清单 9.2 在同时存在多个相同 ID 时 getElementById() 方法的行为
<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>在同时存在多个相同 ID 时 getElementById() 方法的行为</title>
</head>

<body>
    <div id="hzh">第一个hzh</div>
    <div id="hzh">第二个hzh</div>
    <div id="hzh">第三个hzh</div>
    <script>
        var element = document.getElementById('hzh');
        alert(element.innerHTML); // 大部分浏览器都会返回第一个hzh。不过这并不是一个绝对标准
    </script>
</body>

</html>

image

9.3.2 通过标签名检索

可以通过下面这样的方式,使用 Element.getElementsByTagName() 方法来取得具有该标签名的所有节点。标签名还可以使用 '*' 作为通配符。可以通过 '*' 来获取所有元素。

var spanElements = document.getElementsByTagName('span'); // 仅获取span元素
var allElements = document.getElementsByTagName('*');     // 获取所有的元素

Document.getElementById() 是只存在于 Document 对象中的方法,而Element.getElementsByTagName() 则是同时存在于 Document 对象与 Element 对象这两者中的方法。在执行某个 Element 对象的 getElementsByTagName() 方法时,该 Element 对象的子孙节点中具有指定标签名的元素也将被获取(代码清单 9.3)。

代码清单 9.3 getElementById() 与 getElementsByTagName()
<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>getElementById() 与 getElementsByTagName()</title>
</head>

<body>
    <p id="huangzihan">
        <span>hzh1</span>
        <span>hzh2</span>
        <span>hzh3</span>
        <span>hzh4</span>
    </p>
    <p id="hzh">
        <span>黄子涵</span>
    </p>
    <script>
        var huangzihan = document.getElementById('huangzihan');
        // Element 对象中没有 getElementById() 方法
        alert("查看Element对象中有没有getElementById() 方法?");
        alert(huangzihan.getElementById);       // => undefined
        // Element 对象中存在 getElementsByTagName() 方法
        alert("查看Element 对象中是否存在 getElementsByTagName() 方法?");
        alert(huangzihan.getElementsByTagName); // => function getElementsByTagName() { [native code] }
        // 从 huangzihan 的子孙节点中取得元素 span
        var huangzihanSpans = huangzihan.getElementsByTagName('span');
        alert("huangzihan 的子孙节点中span元素的个数:");
        alert(huangzihanSpans.length);          // => 3
        // 从整个文档中获取元素 span
        var allSpans = document.getElementsByTagName('span');
        alert("从整个文档中span元素的个数:");
        alert(allSpans.length);                 // => 4
    </script>
</body>

</html>

image

Live 对象的特征

在这里需要注意的是,getElementsByTagName() 所能取得的对象是一个 NodeList 对象,而不是单纯的 Node 对象的数组。而 NodeList 对象的一大特征就是它是一个 Live 对象。可以写出代码清单 9.4 这样的代码。

代码清单 9.4 Live 对象
<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Live 对象</title>
</head>

<body>
    <div id="hzh">
        <span>黄子涵</span>
        <span>黄子涵是帅哥!</span>
    </div>
    <script>
       var hzh1 = document.getElementsByTagName('span');
       alert("第一次打印span元素的个数:");
       alert(hzh1.length); 
       var hzh2 = document.createElement('span');
       hzh2.appendChild(document.createTextNode('黄子涵是靓仔!'));
       var hzh3 = document.getElementById('hzh');
       hzh3.appendChild(hzh2);
       alert("第二次打印span元素的个数:");
       alert(hzh1.length);
    </script>
</body>

</html>

image

在上面的代码中,最初取得的 hzh1.length 值为 2,这是很显然的。之后,通过 JavaScript 新增了一个 span 元素。再一次显示 hzh2.length 时其值变为了 3。

如果是在新增了 span 之后再执行 getElementsByTagName(),自然不会觉得有什么问题,但这里明明是一个在新增 span 之前就已经取得的 NodeList 对象,却能够知道新增了 span 之后的状态,是不是觉得有点奇怪?而这就是 Live 对象的一个特征。

Live 对象始终具有 DOM 树实体的引用。因此,对 DOM 树做出的变更也会在 Live 对象中得到体现。

9.3.3 通过名称检索

通过 HTMLDocument.getElementsByName() 方法,可以将 name 属性的值作为限定条件来获取属性。不过因为只能在 form 标签或 input 标签等标签中使用 name 属性,所以与 getElementById() 相比,它的使用频率较低。

9.3.4 通过类名检索

通过使用 HTMLElement.getElementsByClassName() 方法,就可以获取指定类名的元素。其中的类名可以指定多个值。如果想要指定多个类名,则需要使用空白符作为分隔字符串。也就是类似于 'classA classB' 的形式。这时,会取得 classA 与 classB 这两个类名所指定的元素。

该方法并不属于 DOM Core 或 DOM HTML 标准,而是一种 HTML5 规定的功能。不过在实际使用中并不需要对此过于在意。

从这是一个在 HTML5 标准中定义的方法这一点上也能知道,只有现代的浏览器才对该方法提供了支持。在 Internet Explorer 8 以及更早的版本中无法使用这一方法。不过其实在很多 JavaScript 库中,都有类似于 getElementsByClassName() 这一方法的实现,所以只要利用库的话,同样能够简单地在Internet Explorer 8 以及更早的版本中使用这样的功能。

9.4 节点的创建与新增

9.5 节点的内容更改

9.6 节点的删除

9.7 innerHTML/textContent

9.8 DOM操作的性能

标签:Level,对象,标签,DOM,HTML,节点
来源: https://www.cnblogs.com/Huang-zihan/p/16269260.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有