## 9.3 DOM扩展
### 9.3.1 选择符API
| 方法 | 描述 |
| --- | --- |
| querySelector() | 接收一个CSS选择符,返回与该模式匹配的第一个元素,如果没有找到匹配的元素,返回null。与getElementsById()类似,这个方法可以通过Document类型或Element类型调用。 |
| querySelectorAll() | 返回的是一个NodeList实例,而其底层实现则类似一组元素的快照,而非不断对文档进行搜索的动态查询。 |
| matchesSelector() | 接收一个CSS选择符,如果调用元素与该选择符匹配,返回true;否则,返回false。 |
### 9.3.2 元素遍历
Element Traversal API为DOM元素添加了以下5个属性:
| 属性 | 描述 |
| --- | --- |
| childElementCount | 返回子元素(不包括文本节点和注释)的个数。|
| firstElementChild | 指向第一个子元素;firstChild的元素版。|
| lastElementChild | 指向最后一个子元素;lastChild的元素版。|
| previousElementChild | 指向前一个同辈元素;previousSibling的元素版。|
| nextElementChild | 指向后一个同辈元素;nextSibling的元素版。|
### 9.3.3 HTML5(DOM相关)
**1. 类相关扩充**
`getElementsByClassName()`:接收包含一个或多个类名的字符串,返回带有指定类的所有与元素的NodeList。(类名不分顺序)
**2. classList属性**
HTML5新增的一种操作类名的方式,可以让操作更简单也更安全。classList属性是心机和类型DOMTokenList的实例,有length属性,可以使用item()方法,也可以使用方括号语法。
| 方法 | 描述 |
| --- | --- |
| add() | 将给定字符串值添加到类名列表中,如果已经存在就不添加了。|
| contains() | 表示列表中是否存在给定的值,如果存在则返回true,否则返回false。|
| remove() | 从列表中删除给定的字符串。|
| toggle() | 如果列表中已经存在给定的值,删除它;如果列表中没有给定的值,添加它。|
**3. 焦点管理**
元素获得焦点的方式有页面加载、用户输入(通常按Tab键)和在代码中调用focus()方法。HTML添加了辅助管理DOM焦点的功能。
`document.activeElement属性`:始终会引用DOOM中当前获得了焦点的元素。默认情况下,文档刚加载完成时,保存的是document.body元素的引用。文档加载期间,为null。
`document.hasFocus()方法`:用于确定文档是否获得了焦点。通过检测文档是否获得了焦点,可以知道用户是不是正在与页面交互。
**4.HTMLDocument的变化**
(1)readyState属性
两个值:loading,正在加载文档;complete,已经加载完文档。
可以通过readyState属性来实现一个指示文档已经加载完成的指示器。
(2)兼容模式
compatMode区分渲染页面的模式是标准的还是混杂的。
两个值:标准模式,CSS1Compat;混杂模式,BackCompat
(3)head属性
HTML5新增了document.head属性
引用文档的`<head>`元素:
~~~
var head = document.head || document.getElementsByTagName("head")[0];
~~~
**5. 字符集属性**
HTML5新增了几个与文档字符集有关的属性。
|属性|描述|
|---|---|
| charset | 表示文档中实际使用的字符集,也可以用来指定新字符集。默认“UTF-16”,可以通过<meta>元素、响应头部或直接设置charset属性修改这个值。|
| defaultCharset |表示根据默认浏览器及操作系统的设置,当前文档默认的字符集。|
通过这两个属性可以得到文档使用的字符编码的具体信息,也能对字符编码进行准确地控制。(无默认的字符集,两者不一样。)
**6. 自定义数据属性**
HTML5规定可以为元素添加非标准的属性,但要添加前缀data-,目的是为元素提供与渲染无关的信息或提供语义信息。
添加自定义属性之后,可以通过元素的**dataset属性**来访问自定义属性的值。dataset属性的值是DOMStringMap的一个实例,即一个名值对儿的映射。
~~~
<div id="myDiv" data-appId="12345" data-myname="Nicholas"></div>
var div = document.getElementById("myDiv");
//取得自定义属性的值
var appId = div.dataset.appId;
var myName = div.dataset.myname;
//设置值
div.dataset.appId = 23456;
div.dataset.myname = "Michael";
if (div.dataset.myname){
alert("Hello, " + div.dataset.myname);
}
~~~
**7.插入标记**
为了简化给文档插入大量新HTML标记的情况,HTML5规范了与插入标记相关的DOM扩展。
(1)innerHTML属性
在读模式下,innerHTML 属性返回与调用元素的所有子节点(包括元素、注释和文本节点)对应的HTML 标记。
在写模式下,innerHTML 会根据指定的值创建新的DOM树,然后用这个DOM树完全替换调用元素原先的所有子节点。
读取Element的 innerHTML 属性作为字符串标记返回那个元素的内容。
~~~
<div id="div"><p>123</p></div>
var d = document.getElementById('div');
d.innerHTML // "<p>123</p>"
~~~
除了获取,还可以设置
~~~
d.innerHTML = '<span>99</span>'
// <div id="div"><span>99</span></div>
~~~
大多数浏览器中,通过innerHTML插入`<script>`并不会执行其中的脚本。
(2)outerHTML属性
在读模式下,outerHTML返回调用它的元素及所有子节点的HTML标签。
在写模式下,outerHTML会根据指定的HTML字符串创建新的DOM子树,然后用这个DOM子树完全替换调用元素。
~~~
d.outerHTML
// "<div id="div"><p>123</p></div>"
~~~
注意:只有Element节点有outerHTML属性,Document节点没有。
(3)insertAdjacentHTML()方法
将任意的HTML标记字符插入到指定的元素“相邻”的位置。
接收两个参数:插入位置和要插入的HTML文本。
第一个参数必须是:“beforebegin”、“afterbegin”、“beforeend”和“afterend”之一。
如下图:
![](https://box.kancloud.cn/18e4ce5cc0ff9802c3558b13f76584dd_747x115.png)
第二个参数是一个HTML字符串。(与innerHTML和outerHTML的值相同)
(4)内存与性能问题
使用本节介绍的方法替换子节点可能会导致浏览器的内存占用问题,尤其是在IE 中,问题更加明显。在**删除带有事件处理程序或引用了其他JavaScript 对象子树时,就有可能导致内存占用问题。**假设某个元素有一个事件处理程序(或者引用了一个JavaScript 对象作为属性),在使用前述某个属性将该元素从文档树中删除后,元素与事件处理程序(或JavaScript 对象)之间的绑定关系在内存中并没有一并删除。如果这种情况频繁出现,页面占用的内存数量就会明显增加。因此,在使用innerHTML、outerHTML 属性方法时,**最好先手工删除要被替换的元素的所有事件处理程序和JavaScript 对象属性。**
**8. scrollIntoView()方法**
srollIntoView()方法可以在所有HTML元素上调用,通过滚动浏览器窗口或某个容器元素,调用元素就可以出现在视口当中。如果给这个方法传入true作为参数,或者不传入任何参数,那么窗口滚动之后会让调用的元素的顶部与视口顶部尽可能平齐。如果传入false作为参数,调用元素会尽可能全部出现在视口当中,(可能的话,调用元素的底部会与是视口底部平齐)不过顶部不一定平齐。
~~~
//让元素可见
document.forms[0].scrollIntoView();
~~~
当页面发生变化时,一般会用这个方法来吸引用户的注意力。实际上,为某个元素设置焦点也会导致浏览器滚动并显示出获得焦点的元素。
### 9.3.4 专有扩展
**1. 文档模式**
**2. children属性**
由于IE9之前的版本与其他浏览器在处理文本节点中的空白符时有差异,因此出现了children属性。
这个属性是HTMLCollection的实例,**只包含元素中同样还是元素的子节点**。除此之外,children属性与childNodes没有什么区别。
**3. contains()方法**
contains()方法:祖先节点即搜索开始的节点调用,接受一个参数,即检测的后代节点。如果被检测的节点是后代节点,返回true,否则返回false。
**4. 滚动**
- 前言
- 第一章 JavaScript简介
- 第三章 基本概念
- 3.1-3.3 语法、关键字和变量
- 3.4 数据类型
- 3.5-3.6 操作符、流控制语句(暂略)
- 3.7函数
- 第四章 变量的值、作用域与内存问题
- 第五章 引用类型
- 5.1 Object类型
- 5.2 Array类型
- 5.3 Date类型
- 5.4 基本包装类型
- 5.5 单体内置对象
- 第六章 面向对象的程序设计
- 6.1 理解对象
- 6.2 创建对象
- 6.3 继承
- 第七章 函数
- 7.1 函数概述
- 7.2 闭包
- 7.3 私有变量
- 第八章 BOM
- 8.1 window对象
- 8.2 location对象
- 8.3 navigator、screen与history对象
- 第九章 DOM
- 9.1 节点层次
- 9.2 DOM操作技术
- 9.3 DOM扩展
- 9.4 DOM2和DOM3
- 第十章 事件
- 10.1 事件流
- 10.2 事件处理程序
- 10.3 事件对象
- 10.4 事件类型
- 第十一章 JSON
- 11.1-11.2 语法与序列化选项
- 第十二章 正则表达式
- 12.1 创建正则表达式
- 12.2-12.3 模式匹配与RegExp对象
- 第十三章 Ajax
- 13.1 XMLHttpRequest对象
- 你不知道的JavaScript
- 一、作用域与闭包
- 1.1 作用域
- 1.2 词法作用域
- 1.3 函数作用域与块作用域
- 1.4 提升
- 1.5 作用域闭包
- 二、this与对象原型
- 2.1 关于this
- 2.2 全面解析this
- 2.3 对象
- 2.4 混合对象“类”
- 2.5 原型
- 2.6 行为委托
- 三、类型与语法
- 3.1 类型
- 3.2 值
- 3.3 原生函数