JavaScript之操作DOM(上)

1. 概述

1.1 DOM

DOM 是 JavaScript 操作网页的接口,全称为“文档对象模型”(Document Object Model)。它的作用是将网页转为一个 JavaScript 对象,从而可以用脚本进行各种操作(比如增删内容)。

浏览器会根据 DOM 模型,将结构化文档(比如 HTML 和 XML)解析成一系列的节点,再由这些节点组成一个树状结构(DOM Tree)。

严格地说,DOM 不是 JavaScript 语法的一部分,但JavaScript 是最常用于 DOM 操作的语言,离开了 DOM,JavaScript 就无法控制网页。

1.2 节点(node)

DOM 的最小组成单位叫做节点(node)。文档的树形结构(DOM 树),就是由各种不同类型的节点组成。
节点的类型有七种,都继承了原生的节点对象 Node

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

1.3 节点树

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

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

2. Node 接口

所有 DOM 节点对象都继承了 Node 接口,拥有一些共同的属性和方法。

2.1 nodeType 属性

nodeType 属性返回一个整数值,表示节点的类型。
不同节点的 nodeType 属性值和对应的常量如下:

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

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

2.2 nextSibling 属性

Node.nextSibling 属性返回紧跟在当前节点后面的第一个同级节点。如果当前节点后面没有同级节点,则返回 null

// HTML 代码如下
// <div id="d1">hello</div><div id="d2">world</div>
var d1 = document.getElementById('d1');
var d2 = document.getElementById('d2');

d1.nextSibling === d2 // true

注意,该属性还包括文本节点和注释节点(<! -- comment -->)。因此如果当前节点后面有空格,该属性会返回一个文本节点,内容为空格。

2.3 previousSibling 属性

previousSibling 属性返回当前节点前面的、距离最近的一个同级节点。如果当前节点前面没有同级节点,则返回 null

// HTML 代码如下
// <div id="d1">hello</div><div id="d2">world</div>
var d1 = document.getElementById('d1');
var d2 = document.getElementById('d2');

d2.previousSibling === d1 // true

注意,该属性还包括文本节点和注释节点。因此如果当前节点前面有空格,该属性会返回一个文本节点,内容为空格。

2.4 父节点 parentNode 和 parentElement 属性

  • parentNode 属性
    parentNode 属性返回当前节点的父节点。对于一个节点来说,它的父节点只可能是三种类型:元素节点(element)、文档节点(document)和文档片段节点(documentfragment)。
    文档节点(document)和文档片段节点(documentfragment)的父节点都是 null。另外,对于那些生成后还没插入 DOM 树的节点,父节点也是 null
  • parentElement 属性
    parentElement 属性返回当前节点的父元素节点。如果当前节点没有父节点,或者父节点类型不是元素节点,则返回 null

注意: Element:网页的各种HTML标签(比如 <body><a> 等)

2.5 childNodes 属性

childNodes 属性返回一个类似数组的对象(NodeList 集合),成员包括当前节点的所有子节点(包括文本节点和注释节点)。

var children = document.querySelector('ul').childNodes;

上面代码中,children 就是 ul 元素的所有子节点。

  • 另:关于 ParentNode.children
    如果当前节点是父节点,就会继承 ParentNode 接口。(只有元素节点(element)、文档节点(document)和文档片段节点(documentFragment)拥有子节点)
    children 属性返回一个 HTMLCollection 实例,成员是当前节点的所有元素子节点。
    注意,children 属性只包括元素子节点,不包括其他类型的子节点(比如文本子节点)

3. NodeList 接口

节点都是单个对象,有时需要一种数据结构,能够容纳多个节点。DOM 提供两种节点集合,用于容纳多个节点:NodeListHTMLCollection
主要区别是,NodeList 可以包含各种类型的节点,HTMLCollection 只能包含 HTML 元素节点。

3.1 NodeList 实例

通过以下方法可以得到 NodeList 实例。

  • Node.childNodes
  • document.querySelectorAll() 等节点搜索方法
document.body.childNodes instanceof NodeList // true

var children = document.body.childNodes;

Array.isArray(children) // false

children.length // 34
children.forEach(console.log)

上面代码中,NodeList实例 children 不是数组,但是具有 length 属性和 forEach 方法。

3.2 静态/动态集合

NodeList 实例可能是动态集合,也可能是静态集合。
所谓动态集合就是一个活的集合,DOM 删除或新增一个相关节点,都会立刻反映在 NodeList实例。
目前,只有 Node.childNodes 返回的是一个动态集合,其他的 NodeList 都是静态集合。

var children = document.body.childNodes;
children.length // 18
document.body.appendChild(document.createElement('p'));
children.length // 19

4. HTMLCollection 接口

4.1 概述

HTMLCollection 是一个节点对象的集合,只能包含元素节点(element),不能包含其他类型的节点。
它的返回值是一个类似数组的对象,但是与 NodeList 接口不同,HTMLCollection没有forEach 方法,只能使用 for 循环遍历。

HTMLCollection 实例都是动态集合,节点的变化会实时反映在集合中。

返回 HTMLCollection 实例的,主要是一些 Document对象的集合属性,比如 document.linksdocument.formsdocument.images等。

document.links instanceof HTMLCollection // true

4.2 id 或 name 属性引用

如果元素节点有 idname 属性,那么 HTMLCollection 实例上面,可以使用 id 属性或 name 属性引用该节点元素。如果没有对应的节点,则返回 null

// HTML 代码如下
// <img id="pic" src="http://example.com/foo.jpg">

var pic = document.getElementById('pic');
document.images.pic === pic // true

上面代码中,document.images 是一个HTMLCollection实例,可以通过<img>元素的 id 属性值,从 HTMLCollection 实例上取到这个元素。

5. ParentNode 接口

节点对象除了继承 Node 接口以外,还会继承其他接口。ParentNode 接口表示当前节点是一个父节点,提供一些处理子节点的方法。ChildNode 接口表示当前节点是一个子节点,提供一些相关方法。
(以下重复文字可看做为:重要的事情多说一遍)

5.1 父节点与 ParentNode 接口

如果当前节点是父节点,就会继承 ParentNode 接口。
由于只有元素节点(element)、文档节点(document)和文档片段节点(documentFragment)拥有子节点,因此只有这三类节点会继承 ParentNode 接口。

5.2 ParentNode.children(只读)

children 属性返回一个 HTMLCollection 实例,成员是当前节点的所有元素子节点。
注意,children 属性只包括元素子节点,不包括其他类型的子节点(比如文本子节点)。如果没有元素类型的子节点,返回值 HTMLCollection 实例的 length 属性为 0
另外,HTMLCollection 是动态集合,会实时反映 DOM 的任何变化。

6. ChildNode 接口

6.1 概述

ChildNode 接口表示当前节点是一个子节点,提供一些相关方法。
如果一个节点有父节点,那么该节点就继承了 ChildNode 接口。

6.2 方法

  • ChildNode.remove()
    remove 方法用于从父节点移除当前节点。
el.remove()

上面代码在 DOM 里面移除了 el 节点。

  • ChildNode.before()
    before 方法用于在当前节点的前面,插入一个或多个同级节点。两者拥有相同的父节点。
    该方法不仅可以插入元素节点,还可以插入文本节点。
var p = document.createElement('p');
var p1 = document.createElement('p');

// 插入元素节点
el.before(p);

// 插入文本节点
el.before('Hello');

// 插入多个元素节点
el.before(p, p1);

// 插入元素节点和文本节点
el.before(p, 'Hello');
  • ChildNode.after()
    after 方法用于在当前节点的后面,插入一个或多个同级节点,两者拥有相同的父节点。用法与before方法完全相同。

  • ChildNode.replaceWith()
    replaceWith 方法使用参数节点,替换当前节点。参数可以是元素节点,也可以是文本节点。

var span = document.createElement('span');
el.replaceWith(span);

上面代码中,el 节点将被 span 节点替换。

参考连接

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

推荐阅读更多精彩内容

  • DOM(文档对象模型)是针对 HTML 和 XML 文档的一个 API。DOM 描绘了一个层次化的节点树,允许开发...
    劼哥stone阅读 771评论 8 6
  • 基本概念 DOM DOM 是 JavaScript 操作网页的接口,全称为“文档对象模型”(Document Ob...
    许先生__阅读 859评论 0 1
  •   DOM(文档对象模型)是针对 HTML 和 XML 文档的一个 API(应用程序编程接口)。   DOM 描绘...
    霜天晓阅读 3,640评论 0 7
  • 一、基本概念 1.1、DOM DOM是JS操作网页的接口,全称为“文档对象模型”(Document Object ...
    周花花啊阅读 3,170评论 0 6
  • 前言:尽管现在有很多优秀的框架,大大简化了我们的DOM操作,但是我们仍然要学好DOM知识来写原生JS,从根本上去理...
    长鲸向南阅读 1,865评论 0 0