JavaScript中的文档对象模型

1. DOM基本介绍
1 什么是DOM
DOM的英语全称为Document Object Model,翻译成中文就 是文档对象模型。也就是说,将整个文档看作是一个对象。而一个文档又是由很多节点组成的, 那么这些节点也可以被看作是一个个的对象。DOM里面的对象属于宿主对象,需要浏览器来作 为宿主。一旦离开了浏览器这个环境,那么该对象将不复存在。同样,上一章我们所介绍的 BOM也是如此,需要浏览器来作为宿主,所以它也是一个宿主对象。
DOM的作用如下:
・浏览器提供的操纵HTML文档内容的应用程序接口
・用于对文档进行动态操作,如增加文档内容,删除文档内容,修改文档内容等等
2 DOM 历史
DOM Level 0:
首先,我们需要确定的是在DOM标准中并没有DOM0级这个级别。所谓
的DOM0级是DOM历史坐标中的一个参照点而已,怎么说呢,DOM0级指的是IE4和N etscape 4.0这些浏览器最初支持的DOM相关方法。主要关注于常见的页面元素,比如图像,链接和表 单。有些现在图像和表单的那些方法,目前依然可以被用在当前版本的DOM中。
DOM Level 1:
于1998年10月成为W3C的推荐标准。DOM1级由两个模块组成:DOM核心 (DOM Core)和DOM HTML。这个版本引入了网页的完整模型,允许在网页的每个部分进行导 航。
DOM Level 2:
对DOM level 1 做了扩展,于20001年出版,引入了流行的 getElementById()方 法,让访问网页上的特定元素变得更加容易。
DOM Level 3:
对DOM level 2做了进一步的扩展,于2004年出版。
3节点类型与节点名称
—个文档是由大量的节点所构成的。而每一个节点都有一个叫做nodeType的属性,用于表明节 点的类型。不同的节点类型对应了不同的数值,具体对应的数值如下表:
节点名称 对应数值
兀素P点 Node.ELEMENT_NODE(1)
属性节点 Node.ATTRIBUTE_NODE ⑵
文本节点 Node.TEXT_NODE ⑶
CDATA节点 Node.CDATA_SECTION_NODE ⑷
实体引用名称节点 Node.ENTRY_REFERENCE_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)
DTD声明节点 Node.NOTATION_NODE(12)
不同的节点对应了不同的节点类型,我们可以通过nodeType属性来获取 到该节点的节点类型
nodeType属性可以和if配合使用,确保不会在错误的节点类型上执行错误的操作
除了获取节点类型以外,我们还可以通过nodeName属性来获取节点的名称,
可以使用nodeValue来获取一个元素节点的文本值
2. 旧的DOM用法
1 document.body
返回网页的<body>元素
2 document.images
返回文档中所有图像的一个节点列表
可以像使用数 组一样来取得每一个图片元素
3 document.links
返回所有具有href属性的<a>元素和<area>元素的一个节点列表
4 document.anchors
返回所有具有name属性的va>元素的一个节点列表
5 document.forms
返回文档中所有表单的一个节点列表
3. 快速查找节点
1 getElementById()
快速锁定id为某个值的节点
2 getElementsByTagName()
通过标签的名称来快速查找节点,不过通 过标签名来查找节点的方式得到的是一个节点列表,我们需要通过类似于数组的方式才能定位到 具体的某一个节点。
3 getElementsByClassName()
className,顾名思义,就是通过类名来查找到元素。而我们知道,类名也是可以有相同的,所 以通过这种方式返回的也会是一个元素列表,
4 document.getElementsByName()
使用这个方法可以访问到对应name值的元素节点。因为节点允许有相同的name值,所以这个方 法返回的也会是一个节点列表。
5 document.querySelector()
这是HTML5新增的查找节点方法,该方法最大的特点在于可以通过CSS的语法来查找文档中所匹 配的第一个元素,注意,只是第一个元素!
6 document.querySelectorAll()
这个方法相比上面的方法多了一个All的标志符,我们可以猜想,这就是会返回所有符合要求的元 素,同样还是使用CSS的语法来进行查找
4. 关系查找节点
1 childNodes 属性
每个节点都有一个childNodes属性,其中保存着一个NodeList的类数组对象。该对象包含了 该节点下面所有的子节点。NodeList对象是自动变化的。
2 children 属性
children属性只返回一个节点下面的所有子元素节点,所以会忽略所有的文本节点和空白节 点
3 firstChild 和 lastChild
接下来我们首先要介绍的是这两个属性,分别是访问一个节点的第一个子节点以及最后一个节 点,示例如下:
<body>
<p id="test1" class="abc">Lorem ipsum dolor sit amet.</p>
<p id="test2">Lorem ipsum dolor sit amet.</p>
<a hr ef="" class="abc"> 链接 1v/a>
<ul id="test3">
<li>item1</li>
<li>item2</li>
<li>item3</li>

</ul>
<script>
let i = document.getElementById("test3"); console.log(i.firstChild);
</script>
</body>
效果:
► #text
可以看到这里就访问到了 <ul>下面的第一个子节点,但是其实这个节点是一个空白节点,什么 意思呢?就是说在DOM里面会将空格和换行也视为是一个节点。这样的节点叫做空白节点。如 果我现在将<ul>元素和vli>元素之间的空白给删除掉,那么第一个子元素就应该为<ul>下 面的第一个<li> ,如下:
<body>
<p id="test1" class="abc">Lorem ipsum dolor sit amet.</p>
<p id="test2">Lorem ipsum dolor sit amet.</p>
<a hr ef="" class="abc"> 链接 1</a>
<ul id="test3">
<li>item1</li>
<li>item2</li>
<li>item3</li>
</ul>
<script>
let i = document.getElementById("test3");
console.log(i.firstChild);
</script>
</body>
效果:
<li>iteml</li>
这时<ul>下面的第一个子元素就变为了第一个<li>元素。
如果想要在保持之前的HTML结构的基础上获取第一个<li>元素的内容的话,就只有层层往下 找,如下:
<body>
<p id="test1" class="abc">Lorem ipsum dolor sit amet.</p>
<p id="test2">Lorem ipsum dolor sit amet.</p>
<a hr ef="" class="abc"> 链接 1</a>
<ul id="test3">
<li>item1</li>
<li>item2</li>
<li>item3</li>
</ul>
<script>
let i = document.getElementById("test3"); console.log(i.firstChild.nextSibling.firstChild);
</script>
</body>
效果:
"iteml"
lastchild基本上就和刚才的fi rstChild相反,获取的是子节点里面的最后一个节点,示例 如下:
<body>
<p id="test1" class="abc">Lorem ipsum dolor sit amet.</p>
<p id="test2">Lorem ipsum dolor sit amet.</p>
<a hr ef="" class="abc"> 链接 1</a>
<ul id="test3">
<li>item1</li>
<li>item2</li>
<li>item3</li>
</ul>
<script>
let i = document.getElementById("test3"); console.log(i.lastChild);
</script>
</body>
效果:
► #text

这里也是获取到的是一个空白节点
4 parentNode
获取父级节点的属性
5 previousSibling 和 nextSibling
pr eviousSiblings属性返回同一父节点下的前一个相邻节点。如果该节点已经是父节点的第一
个节点,则返回null,示例如下:
<body>
<p id="test1" class="abc">Lorem ipsum dolor sit amet.v/p>
<p id="test2">Lorem ipsum dolor sit amet.v/p>
<a hr ef="" class="abc"> 链接 1</a>
<ul id="test3">
<li>item1v/li>
<li>item2v/li>
<li>item3v/li>
</ul>
<script>
let i = document.getElementById("test3");
console.log(i);

console.log(i.previousSibling.previousSibling);
</script>
</body>
效果:
► <ul id="test3">...</ul>
<a href class=,,abc">链接l</a>
连续写两次pr eviousSiblings,可以跳过第一个空白节点,定位到va>节点。
接下来我们来看一下nextSibling , nextSibling属性返回同一父节点的下一个相邻节点。如
果节点是父节点的最后一个节点,则返回null,示例如下:
<body>
<p id="test1" class="abc">Lorem ipsum dolor sit amet.v/p>
<p id="test2">Lorem ipsum dolor sit amet.v/p>
<a hr ef="" class="abc"> 链接 1v/a>
<ul id="test3">
<li>item1v/li>
<li>item2v/li>
<li>item3v/li>
</ul>
<script>
let i = document.getElementById("test1"); console.log(i.nextSibling.nextSibling);
</script>
</body>
效果:这里也是同样,如果只写一个nextSibling ,那么访问到的是一个空白节点,连续写两 个,就跳过了这个空白节点,访问到了下一个元素节点。
<p id="test2,l>Lorem ipsum dolor sit amet・</p>
6 previousElementSibling 和 nextElementSibling
把前后的换行也算作是一个空白节点,这样的处理确实也有太麻烦了。所以,现在添加上
了 pr eviousElementSibling和nextElementSibling这两个属性,直接用于查询某一^节点
的上一个或者下一个元素节点,示例如下:
<body>
<p id="test1" class="abc">Lorem ipsum dolor sit amet.</p>
<p id="test2">Lorem ipsum dolor sit amet.</p>
<a hr ef="" class="abc"> 链接 1</a>

<ul id="test3">
<li>item1</li>
<li>item2</li>
<li>item3</li>
</ul>
<script>
let i = document.getElementById("test2"); console.log(i.previousElementSibling);
</script>
</body>
效果:
<p id=l,testl" class^'abc'^Lorem ipsum dolor sit amet・</p>
再来看一^? nextElementSibling属性的例子
<body>
<p id="test1" class="abc">Lorem ipsum dolor sit amet.</p>
<p id="test2">Lorem ipsum dolor sit amet.</p>
<a hr ef="" class="abc"> 链接 1</a>
<ul id="test3">
<li>item1v/li>
<li>item2v/li>
<vli>item3v/li>
</ul>
<script>
let i = document.getElementById("test2"); console.log(i.nextElementSibling); </script>
</body>
效果:

5. 节点操作
1创建和添加节点
createElement()的方 法,允许我们来创建一个元素节点
insertBefore() 是添加在节点的前面
2删除节点
删除节点的语法如下:
父节点.removeChild (子节点)
3替换节点
语法如下:
父节点.replaceChild(新节点,旧节点)
4克隆节点
克隆节点分为浅克隆和深克隆,只需要向cloneNode()方法传入一个布尔值即 可实现浅克隆和深克隆。
克隆节点的语法如下:
节点.clone (布尔值)
浅克隆
所谓浅克隆,就是指指克隆某一个节点,仅仅是克隆该节点而已,方法参数传入false 
深克隆
所谓深克隆,就是指复制某个节点和其子节点,需要传入的布尔值为true。
5文档碎片
前面,我们已经学会了向文档里面添加节点,但是存在一个问题,那就是如果要添加大量节点 的话,这种逐个添加的方法会显得效率很低,因为添加一个节点就会刷新一次页面。这个时候, 我们就可以使用DOM里面提供的cr eateElementF ragment()方法,将节点先添加在一个文档碎 片里面,然后最后再一次性添加到文档里面
6创建注释节点
在DOM中提供了创建注释节点的方法createComment(),使用该方法可以创建一个注 释
7实时集合
节点的相关信息是实时进行改变的。举个例子,如果我们添加或者删除 了一个节点,那么当我们访问父节点的长度时马上就会有改变
这里有一个坑,使用以前的DOM方法,例如document.getElementsByTagName来获取到的元 素是实时集合的,返回的是HTMLCollection,而使用新的que rySelecto rAll来获取到的元素 集合不是实时集合,返回来的是NodeList ,这个的长度是不会实时更新的。
6快速获取节点内容
1 innerHTML 和 innerText
innerText用于获取元素节点的文本值,而innerH TML则用 于用户元素节点下面的所有东西,包括H TML标签。
修改bod y里面的节点内容,我不需要费尽周折的删除已有节点,然后创建新的节点这些 步骤,直接修改body的i nnerHTML的内容即可,非常的方便简洁
2 textContent (扩展)
过该属性,我们可以直接获取到一个元素节点的文本 内容
面的innerText好像也是获取元素节点的文本值,两者有什么区别 么?
区别主要体现在如下几点:
•textContent 会获取 style= "displaymone11 中的文本,而 innerText 不会
•textContent会获取style标签里面的文本,而innerText不会
•innerText对IE的兼容性较好
•textContent虽然作为标准方法但是只支持IE8+以上的浏览器
6. 快速获取节点内容
1 innerHTML 和 innerText
innerText用于获取元素节点的文本值
而innerH TML则用 于用户元素节点下面的所有东西,包括H TML标签
7. 属性和类的操作
1元素属性操作相关方法(扩展)
获取和设置元素属性
getAtt ribute()顾名思义就是获取到元素节点的属性值
setAtt ri bute()则是设置元素节 点的属性值
删除元素属性
使用DOM里面提供的removeAttribute()方法来进行删除,直接传入要 删除的属性名作为参数即可
使用removeNamedItem()方法来删除属性,也是同样要先用attributes获取到元 素节点的属性集合
获取属性索引
item()方法,该方法也是在属性集合的基础上使用,传入的参数为数字,可以定位到某一个属 性上面,
2元素的类的相关操作(扩展)
的DOM里面可 以使用classList来获取一个元素节点所有的类
通过className这个属性来获取DOM元素的 类,返回的值是一个字符串
添加类
DOM里面也新添加了一个add()方法来给一个元素节点快速添加类
删除类
通过remove()方法来移除一个元素节点的类,也是要使用到类的集合classList上面
切换类
toggle()方法是一个非常有用的方法,可以用来对类进行切换。如果元素节点没有给出的类, 就添加该类,如果有该类,就删除该类。如果类被添加了,就返回true,如果是被删除了,就返 回false。
3元素属性设置通用方法
通过点来对属 性和类进行操作
这里我们通过点来设置了 DOM元素的属性,一般情况下,建议使用这种方式来访问或设置属 性。不过有些情况例外,因为这种方式只能设置或访问标签固有属性的值,而自定义的属性它是 无法获取或设置的。比如给<p>元素设置name属性就无法成功,这是因为<p>元素本身是没 有name属性。如果采用setAtt ri bute方法就可行。
还需要注意的就是关键字命名的属性也需要特殊对待,例如class和for属性。
如果是class属性,因为这是一个关键字,所以需要通过className来进行操作(这个上面已经介 绍过了),如果是for属性,因为这也是一个关键字,所以需要通过htmlFor来进行操作。
4自定义属性
自定义属性,按照H TML5的规范应该尽量使用data -作为前缀,比如给<p>元素添加 —个自定义属性power,应该设置为data-power 
获取data-属性,可以使用DOM里面的getAtt ribute()方法来获取
使用标签中的dataset属性
test1.dataset.power = 'high speed';
这个dataset是每个元素节点都有的属性,它指向所有以data-开头的属性集合。不过在获取或 设置的时候不需要加上这个前缀。
dataset是每个元素节点都有的属性,它指向所有以data-开头的属性集合。不过在获取或 设置的时候不需要加上这个前缀
data-属性的名称包含连字符,那么需要使用驼峰命名法
8. 操作CSS
tyle属性,通过这个属性就可以修改任何元素节点的样式规则
在CSS里面有一些属性是采用的横杠隔开的,例如:background-color ,而如 果要用DOM来修改样式的话,需要修改为驼峰命名法,也就是backgroundColor
9. 操作表格
1获取表格的行和列
通过rows和cells来获取到一个表格对象的 行与列
如果需要修改表格里面的内容,只需要定位到具体的单元格然后重新赋值即可
2遍历表格的内容
遍历表格的内容也是使用双层for循环来搞定的
3表格插入新的行与列
insertRow()以及insertCell()这两个方法来为表格插入行与列,语法如下:
inserRow(position):在表格对象的指定位置上插入一^新行。
insertCell(postion):在rows集合中的指定位置上插入一个新的单元格。
4删除行与列
deleteRow(postion):删除表格对象上指定位置的一行。
deleteCell(postion):删除在rows集合中指定位置上的一个单元格。
5表格其他相关属性和方法
表格的属性或方法 作用
caption 指向<caption>元素(如果存在)
tHead 指向<thead>元素(如果存在)
tBodies 指向<tbody>元素(如果存在)
tFoot 指向<tFoot>元素(如果存在)
rows 表格中所有行的集合
cells —行里面所有单元格的集合
createCaption。 创建<caption>元素并将其放入表格
createTHeadO 创建<thead>元素并将其放入表格
createTFoot。 创建<tFoot>元素并将其放入表格
deleteCaption。 删除<caption>元素


deleteTHead() 删除<thead>元素
deleteTFoot。 删除<tFoot>元素
insertRow(postion) 在表格对象的指定位置上插入一个新行
deleteRow(postion) 删除表格对象上指定位置的一行
insertCell(postion) 在rows集合中的指定位置上插入一个新的单元格
deleteCell(postion) 删除在rows集合中指定位置上的一个单元格

posted @ 2019-07-28 17:32  风雨载明  阅读(704)  评论(0编辑  收藏  举报