JavaScript 中的 文档对象模型DOM

前言:在JavaScript中,DOM操作虽然公认的不好用,但它是最基础的,那么就让我们通过本文就来认识一下DOM的基本概念、一些常用的API以及一些需要注意的知识点。


1、DOM 到底是个什么鬼

文档对象模型 (Document Object Model ,即DOM) 是HTML和XML文档的编程接口。它提供了对文档的结构化的表述,并定义了一种方式可以使从程序中对该结构进行访问,从而改变文档的结构,样式和内容。DOM 将文档解析为一个由节点和对象(包含属性和方法的对象)组成的结构集合。简言之,它会将web页面和脚本或程序语言连接起来。

文档对象模型将 web 页面与到脚本或编程语言连接起来。通常是指 JavaScript,但将 HTML、SVG 或 XML 文档建模为对象并不是 JavaScript 语言的一部分。DOM模型用一个逻辑树来表示一个文档,树的每个分支的终点都是一个节点(node),每个节点都包含着对象(objects)。DOM的方法(methods)让你可以用特定方式操作这个树,用这些方法你可以改变文档的结构、样式或者内容。节点可以关联上事件处理器,一旦某一事件被触发了,那些事件处理器就会被执行。

通俗的说,DOM就是将页面中的元素通过相应的构造方法,转换成对象,使得我们可以在JS中使用。转换成的对象的原型最终指向Node对象

2、节点

DOM 的最小组成单位叫做节点(node)。文档的树形结构(DOM 树),就是由各种不同类型的节点组成。每个节点可以看作是文档树的一片叶子。

节点的类型有以下七种,浏览器提供一个原生的节点对象Node,而这七种节点都继承了Node,因此具有一些共同的属性和方法:

  • Document:整个文档树的顶层节点
  • DocumentType:doctype标签(比如<!DOCTYPE html>)
  • Element:网页的各种HTML标签(比如<body>、<a>等)
  • Attribute:网页元素的属性(比如class="right")
  • Text:标签之间或标签包含的文本
  • Comment:注释
  • DocumentFragment:文档的片段

3、节点树

一个文档的所有节点,按照所在的层级,可以抽象成一种树状结构。这种树状结构就是 DOM 树。它有一个顶层节点,下一层都是顶层节点的子节点,然后子节点又有自己的子节点,就这样层层衍生出一个金字塔结构,倒过来就像一棵树。

浏览器原生提供document节点,代表整个文档。

文档的第一层只有一个节点,就是 HTML 网页的第一个标签<html>,它构成了树结构的根节点(root node),其他 HTML 标签节点都是它的下级节点。

除了根节点,其他节点都有三种层级关系。

  • 父节点关系(parentNode):直接的那个上级节点
  • 子节点关系(childNodes):直接的下级节点
  • 同级节点关系(sibling):拥有同一个父节点的节点

DOM 提供操作接口,用来获取这三种关系的节点。比如,子节点接口包括firstChild(第一个子节点)和lastChild(最后一个子节点)等属性,同级节点接口包括nextSibling(紧邻在后的那个同级节点)和previousSibling(紧邻在前的那个同级节点)属性。

4、节点类型 Node.nodeType

nodeType属性返回一个整数值,表示节点的类型。

document.nodeType // 9
上面代码中,文档节点的类型值为9。

Node 对象定义了几个常量,对应这些类型值。如:
document.nodeType === Node.DOCUMENT_NODE // true
上面代码中,文档节点的nodeType属性等于常量Node.DOCUMENT_NODE。

不同节点的nodeType属性值和对应的常量如下。

文档节点(document):9,对应常量Node.DOCUMENT_NODE
元素节点(element):1,对应常量Node.ELEMENT_NODE
属性节点(attr):2,对应常量Node.ATTRIBUTE_NODE
文本节点(text):3,对应常量Node.TEXT_NODE
文档片断节点(DocumentFragment):11,对应常量Node.DOCUMENT_FRAGMENT_NODE
文档类型节点(DocumentType):10,对应常量Node.DOCUMENT_TYPE_NODE
注释节点(Comment):8,对应常量Node.COMMENT_NODE

最常用的有两个,一定要记住:元素节点的值 1 和文本节点的值 3

确定节点类型时,使用nodeType属性是常用方法。如:

var node = document.documentElement.firstChild;
if (node.nodeType === Node.ELEMENT_NODE) { // 或者直接写成 node.nodeType === 1
  console.log('该节点是元素节点');
}

5、常用的DOM操作

  • createElement
    createElement通过传入指定的一个标签名来创建一个元素,如果传入的标签名是一个未知的,则会创建一个自定义的标签,注意:IE8以下浏览器不支持自定义标签。
    如:var div = document.createElement("div");

  • appendChild
    appendChild 即将指定的节点添加到调用该方法的节点的子元素的末尾。调用方法如下:parent.appendChild(child);
    child节点将会作为parent节点的最后一个子节点。

  • document.getElementById
    这个接口很简单,根据元素id返回元素,返回值是Element类型,如果不存在该元素,则返回null。
    使用这个接口有几点要注意:
    (1)元素的Id是大小写敏感的,一定要写对元素的id
    (2)HTML文档中可能存在多个id相同的元素,则返回第一个元素(当然多个同名id是不符合规范的)
    (3)只从文档中进行搜索元素,如果创建了一个元素并指定id,但并没有添加到文档中,则这个元素是不会被查找到的

  • document.getElementsByTagName
    这个接口根据元素标签名获取元素,返回一个即时的HTMLCollection类型

  • document.getElementsByClassName
    这个API是根据元素的class返回一个即时的HTMLCollection,

  • document.querySelectordocument.querySelectorAll
    这两个api很相似,通过css选择器来查找元素,注意选择器要符合CSS选择器的规则。

  • childNodes:返回一个即时的NodeList,表示元素的子节点列表,子节点可能会包含文本节点,注释节点等。
    children:一个即时的HTMLCollection,子节点都是Element,IE9以下浏览器不支持。

  • getAttribute
    getAttribute返回指定的特性名相应的特性值,如果不存在,则返回null或空字符串。用法如下:
    var value = element.getAttribute("id");

  • getBoundingClientRect
    getBoundingClientRect用来返回元素的大小以及相对于浏览器可视窗口的位置,用法如下:var clientRect = element.getBoundingClientRect();
    clientRect是一个DOMRect对象,包含left,top,right,bottom,它是相对于可视窗口的距离,滚动位置发生改变时,它们的值是会发生变化的。除了IE9以下浏览器,还包含元素的height和width等数据,具体可查看MDN链接

6、DOM 的各种 API

由于DOM中的API非常多,这里不一一列举,仅列出几个需要注意的,其余的可以点击链接,查看相应的MDN文档。

这三对API的区别需要了解一下:

  • isEqualNodeisSameNode
    isEqualNode 表示相等,即两个节点的值是相等的
    isSameNode 表示相同,即两个节点就是同一个
    注意,节点中使用===运算符,指的是same相同的一个节点。

  • innerTexttextContent
    1.textContent 会获取所有元素的内容,包括<script><style> 元素,然而 innerText不会。
    2.innerText 受 CSS 样式的影响,并且不会返回隐藏元素的文本,而textContent会。
    3.由于 innerText 受 CSS 样式的影响,它会触发重排(reflow),但textContent 不会。
    4.与 textContent 不同的是, 在 Internet Explorer (对于小于等于 IE11 的版本) 中对 innerText 进行修改, 不仅会移除当前元素的子节点,而且还会永久性地破坏所有后代文本节点(所以不可能再次将节点再次插入到任何其他元素或同一元素中)。

  • innerTextinnerHTML
    innerText 表示 将里面的内容都一律看做文本
    innerHTML 会将内容看做HTML元素(包括标签甚至script脚本),慎用

7、一些需要注意的知识点

  • DOM的最小组成单位叫做 Node
  • 节点的类型有七种 :DocumentDocumentTypeElementAttributeTextCommentDocumentFragment(详细请看上文“4、节点类型 Node.nodeType”)
  • DOM 树的根节点是 html
  • document.body.nodeName得到的结果是'BODY',(注意,nodeName得到的节点名称都是大写,除了svg)
  • 有这样的html结构,求x.nextSibling 的值是
<div id=x></div>
<div id=y></div>

结果为:回车构成的文本节点,因为nextSibling属性包括文本节点(如回车、空格)、注释节点等。

  • 有这样的HTML结构,求parent1.childNodes 的值
<div id=parent1><div id=child1></div></div>

结果为: {0:child1, length:1} 伪数组

  • parent.childNodes 是动态集合。所谓动态集合就是一个活的集合,DOM树删除或新增一个相关节点,都会立刻反映在NodeList接口之中。
    document.querySelectorAll方法返回的是一个静态集合。DOM内部的变化,并不会实时反映在该方法的返回结果之中。
  • HTMLCollection与NodeList的区别有:
    HTMLCollection实例对象的成员只能是Element节点,NodeList实例对象的成员可以包含其他节点。
    HTMLCollection实例对象可以用id属性或name属性引用节点元素,NodeList只能使用数字索引引用。
  • ChildNode接口用于处理子节点(包含但不限于Element子节点)。Element节点、DocumentType节点和CharacterData接口,部署了ChildNode接口。凡是这三类节点(接口),都可以使用:remove()before()after()replaceWith()

8、参考链接

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容