[关闭]
@demonly 2017-10-13T12:57:03.000000Z 字数 14260 阅读 958

DOM

JavaScript


在 HTML 页面中文档元素始终为 <html> 元素。

Node

以下列出常用的节点类型,有关 XML 的节点类型暂时不列出。

节点类型 nodeName nodeValue nodeType
Element Tag name null 1
Attr 属性名称 属性值 2
Text text 节点内容 3
Comment comment 注释文本 8
Document document null 9
DocumentFragment document fragment null 11

节点关系

每个节点都有一个 childNodes 属性,其中保存着 NodeList 对象。NodeList 对象与数组不同的地方在于 NodeList 对象会根据 DOM 树的更新而实时更新的,而不是在我们第一次访问它时拍下的快照。

Node 类型都具有以下属性和方法:

操作节点

Document

文档的子节点

文档信息

document 对象的属性中保存着与表现的网页相关的信息。

查找元素

取得一个元素可以使用 Document 对象的特定方法。

  1. var myImage = image.namedItem("myImage")
  2. var myImage = image["myImage"]

特殊集合

文档写入

document 可以将输出流写入到网页中,这个能力体现在4个方法中。

在文档加载完毕后调用 document.write 将会重写整个页面。

Element

属性:

方法:

使用 document.crateElement()方法可以创建新元素,这个方法接受一个参数,即标签名。创建之后的元素不会被加入到文档树中,需要用操作节点的方法将新节点加入文档树。

attributes

元素的每一个特性都用一个 Attr 节点表示,每个节点都保存在 NameNodeMap 对象中。这个对象可以通过方括号访问集合中的元素。

在遍历元素特性的场合可以使用这个方法。

Text

可以通过 nodeValue 属性和 data 属性可以访问或者修改文本节点的内容。通过 length 属性获取文本的字符数。使用下列方法可以操作文本节点的内容。

通过修改属性的方式修改文本的内容会对文本进行编码。

可以使用 document.createTextNode()方法创建新的文本节点,这个方法接受一个参数,文本节点的内容。与设置已有文本节点的值一样,这个方法设置的文本也会进行编码。相邻的同胞文本节点会连起来显示,中间不会有空格。

normalize()方法规范化子节点中的文本节点。子节点中如果有空文本节点则删除,有相邻两个文本节点则合并为一个。

Comment

与文本节点相似,不过没有 splitText()方法,用 createComment()方法创建新的注释节点。

Attr

Attr 对象有三个属性,name 是特性名称,value 是特性的值,specified 用于区别特性是在代码中指定的还是默认的。
使用 document.createAttribute()创建特性节点,传入特性名称。

DOM 操作技术

动态脚本

动态脚本指在页面加载时不存在,通过修改 DOM 动态添加的脚本。创建动态脚本既可以插入外部文件也可以直接插入 JavaScript 代码。

  1. var script = document.createElement("script");
  2. script.type = "text/javascript";
  3. script.src = "client.js"
  4. document.body.appendChild(script);

可以通过设置 script.text 属性来直接在文档中插入 JavaScript 代码。在 IE 以外的浏览器中也可以直接在 script 元素里添加一个文本节点。

  1. var script = document.createElement("script");
  2. script.type = "text/javascript";
  3. script.text = code;
  4. document.body.appendChild(script);

当 script 元素被插入到文档中时,其中的 JavaScript 代码将被立即执行。

动态样式

动态样式与动态脚本类似,可以通过创建 link 元素的方式插入外部文件,或者通过创建 style 元素直接插入 CSS 代码。

在 style 元素中插入文本节点来设置样式。

  1. var style = document.createElement("style");
  2. script.type = "text/css";
  3. style.appendChild(document.createTextNode(code));
  4. document.body.appendChild(style);

操作表格

如果要用创建元素的方式创建一个表格,将会产生很长的代码。因此 HTML DOM 微表格添加了一些属性和方法。
<table>元素添加的属性和方法如下。

<tbody>元素添加的属性和方法如下。

<tr>元素添加的属性和方法如下。

使用 NodeList

NodeList、NamedNodeMap 和HTMLCollection 都是动态的,每次访问都会更新,所以可能会出现无限循环的情况。一般来说应该尽量减少对 NodeList 的访问,可以将 NodeList 转换成数组来防止它更新。

样式

访问元素的样式

只要取得一个 DOM 元素的引用就可以通过其 style 对象的对应属性来设置样式,其中 float 属性例外,float 是 javascript 的保留字。在 IE 中对应的属性是 styleFloat,而在其他浏览器中相应的属性名是 cssFloat。

DOM 样式属性和方法

DOM2级中为 style 对象定义了一系列的属性和方法。

直接对 CSSText 属性写入会覆盖掉之前 style 特性中的所有属性。
通过能 length 属性、item()方法和 getPropertyValue()方法可以实现对 style 特性的遍历。

计算的样式

DOM2级为 decument.defaultView 对象提供了 getComputedStyle()方法,这个方法接收两个参数,要取得的样式的元素和一个伪元素字符串,不需要伪元素的话第二个参数可以是 null。这个方法返回一个包含了这个元素所有计算后样式的 CSSStyleDeclaration 对象,通过这个对象可以访问这些计算后样式。值得注意的是对于 border 这种包含了许多属性的属性并不一定会有返回值,例如左右边距不一样的话这个属性的返回值就会是空字符串。如果分别设置同样的四个边距,border 会返回汇总的返回值。此外计算后的样式是只读的。

操作样式表

CSSStyleSheet 类型表示样式表,继承自 StyleSheet 类型,包括<style>中定义的样式表和<link>引入的样式表。这个对象中的除 disabled 以外的属性都是只读的。以下是继承来的属性。

以下是 CSSstyleSheet 类型特有的属性。

应用于文档中的样式表通过 document.styleSheet 集合来表示。也可以通过直接访问<style><link>元素的 sheet 属性来取得样式表对象。在 IE 中为 styleSheet 属性。

CSS 规则

CSSRule 对象表示样式表中的每一条规则,CSSRule 对象包含以下属性。

通常修改样式都只需要用到 style 属性。

创建规则

使用 insertRule 规则可以在现有样式表中插入规则。例如sheet.insertRule("body {background-color:#FFF}",0)
而在 IE 中仅有与之类似的方法 addRule(),这个方法接收三个参数,选择符文本、CSS 样式信息和插入的位置。例如sheet.addRule("body","background-color:#FFF"),0

元素大小

偏移量

通过 offsetParent 的offsetTop 属性循环相加可以最终得到元素相对于整个页面的偏移量。

客户区大小

客户区大小指元素内容及其内边距所占据的空间大小。clientWidth 和clientHeight 分别表示客户区的宽度和高度。在确定视口大小时可以使用 document.documentElement 或者 document.body 的这两个属性,在 IE7以前必须使用后者。

滚动大小

确定文章内容区域大小时可以使用 document.scrollHeight 或者 document.body.scrollHeight 这两个属性,在 IE 中必须使用后者。

确定元素大小

元素对象都拥有 getBoundingClientRect()方法,这个方法返回一个对象。这个对象拥有四个属性 left、top、right、bottom,它们表示该元素相对于视口的位置。

遍历

DOM2定义了两个用于遍历 DOM 结构的类型,NodeIterator 和TreeWalker,这两个对象能够对 DOM 结构进行深度优先遍历。IE 不支持 DOM 遍历。

NodeIterator

通过 creatNodeIterator()方法可以创建 NodeIterator 类型的实例,这个方法接受四个参数。

  • root:想要做为起点的节点。
  • whatToShow:表示要访问的哪些节点的数字代码。
  • filter:是一个 NodeFter 对象,或者一个表示应该接受或者拒绝某种特定节点的函数。
  • entityReferenceExpansion:布尔值,表示是否要扩展实体引用。(与 XML 有关)

其中 whatToShow 参数是一个位掩码,通过按位或操作符可以应用多个过滤器。NodeFter.SHOW_ALL 表示显示所有,NodeFter.SHOW_ELEMENT 表示显示元素节点,以此类推。

filter 参数可以指定自定义 NodeFilter 对象或者指定一个节点过滤器函数。

  • NodeFilter 对象
    NodeFilter 对象只有一个 acceptNode()方法。将遍历到的节点传入这个方法,然后这个方法返回 NodeFilter.FILTER_ACCEPT 或者 NodeFilter.FILTER_SKIP 分别表示访问和不访问这个节点。这个对象不能够创建实例。

  • 过滤器函数
    这个函数的形式与 accept()方法十分类似,不再赘述

下面是两个例子。

  1. var filter = {
  2. acceptNode: function(node) {
  3. return node.tagname.toLowerCase() == 'p' ?
  4. NodeFilter.FILTER_ACCEPT :
  5. NodeFilter.FILTER_SKIP
  6. }
  7. };
  8. var iterator = document.creatNodeIterator( root, NodeFilter.SHOW_ELEMENT, filter, false);
  1. var iterator = document.creatNodeIterator( root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT, filter, false);
  2. var node = iterator.nextNode()
  3. while (node != null) {
  4. alert(node.tagname);
  5. node = iterator.nextNode;
  6. }

NodeIterator 类型有两个主要方法,nextNode()方法和 previousNode()方法,这两个方法用于在深度优先遍历中前进一个节点或者后退一个节点。NodeIterator 对象在刚创建时 nextNode()返回根节点,当遍历完成后 nextNode()返回 null。

TreeTalker

TreeTalker 是NodeIterator 的升级版,它还拥有以下方法。

document.creatTreeTalker()方法与 document.creatNodeIterator()方法接受同样的四个参数。 但是这个方法中的 filter 的返回值还接受 NodeFilter.FILTER_REJECT。这个返回值同样会跳过这个节点,但是与 NodeFilter.FILTER_SKIP 不同的是它还会跳过它的整个节点树。

IE 不支持 DOM 遍历。

范围

使用 creatRange()方法可以创建 DOM 范围,DOM 范围由 range 类型的实例表示,这个类型包含了一些属性。

用 DOM 范围实现简单选择

使用范围来选择文档的一部分,简单的方式就是使用范围的 selectNode()方法和 selectNodeContents()方法来直接选择某个节点,前者不包括该节点本身。
为了更加精细地控制范围,还可以是用以下方法。

用 DOM 范围实现复杂选择

要创建复杂的范围就要使用 setStart()和 setEnd()两个方法。这两个方法都接受两个参数,一个参照节点和一个偏移量。参照节点就是 startContainer,偏移量就是 startOffset。

操作 DOM 范围中的内容

创建范围时,内部会为这个范围创建一个文档片段,这个文档片段的结构必须完整。如果是选取了文本节点的一个部分,那么范围会自动为其补齐开标签和闭标签。范围可以通过一系列方法来进行操作。

插入 DOM 范围中的内容

折叠 DOM 范围

比较 DOM 范围

compareBoundaryPoint()方法确定多个范围之间是否存在共同的起点或者终点。这个方法接受两个参数:表示比较方式的常量值和要比较的范围。以下是表示比较方式的常量值。
- Range.START_TO_START(0):比较第一个范围的起点和第二个范围的起点。
- Range.START_TO_END(1):比较第一个范围的起点和第二个范围的终点。
- Range.END_TO_END(2):比较第一个范围的终点和第二个范围的终点。
- Range.END_TO_START(3):比较第一个范围的终点和第二个范围的起点。

  1. alert(range1.START_TO_START, range2)

如果第一个点在第二个点之前这个方法返回-1,重合返回0,在之后返回1。

复制 DOM 范围

cloneRange()方法复制调用这个方法的范围,修改该范围的端点不会影响原范围。

清理 DOM 范围

detach()方法清理调用这个方法的范围。

选择符 API

querySelector()方法

querySelector()方法接受一个 CSS 选择符,返回与该选择符匹配的第一个元素。

  1. document.querySelector(".container")

querySelectorAll()方法

querySelectorAll()方法与 querySelector()方法类似,只不过这个方法返回的是一个 NodeList,这个 NodeList 包含所有符合条件的元素,但是它不会自动更新

支持这两个方法的浏览器有 IE 8+、Firefox 3.5+、Safari 3.1+、Chrome 和Opera 10+

matchesSelector()方法

Element 新增了machesSelector()方法,这个方法接受一个 CSS 选择符,如果调用元素与选择符匹配则返回 true。

Chrome、Opera 和 FireFox 将这个方法实现为了 matches() 方法。

IE9+ 将这个方法实现为了 msMatchesSelector() 方法。

元素遍历

对于元素间的空格,不同的浏览器有不同的行为,为了弥补这一差异 Element Traversal 规范新定义了一组属性。以下属性中不包括文本节点和注释。

支持这一规范的只有 IE 9+、Firefox 3.5+、Safari 4+、Chrome 和Opera 10+。

HTML5

HTML5中定义了大量的 JavaScript API。

getElementByClassName()方法

这个方法既可以传入一个类名,也可以传入多个类名,先后顺序不重要。这个方法的返回值是 HTMLCollection,会随着 DOM 树的变化自动更新。

classList 属性

元素的 classList 属性保存了元素的所有类名,这个属性指向一个 DOMTokenList 对象,这个对象类似于 NodeList 对象。

DOMTokenList 对象有一系列的方法。

  1. div.classList.remove("user")

焦点管理

document.activeElement 始终引用获得了焦点的元素,获取焦点的方式有页面加载、用户输入和在代码中调用 focus()方法。

默认情况下,document.activeElement 指向 document.body 元素。加载时 document.activeElement 的值为 null。

document.hasFocus()方法确定文档是否获得了焦点,从而确定用户是否正在与页面交互。

HTMLDocument 的变化

readyState 属性

document.readyState 指示文档是否加载完毕,"loading"表示正在加载,"complete"表示已加载完毕。

字符集属性

document.charset 属性表示文档使用的字符集。
document.defaultCharset 属性表示浏览器及操作系统的默认字符集。

自定义数据属性

HTML5 规定可以为为元素添加非标准的属性,但要添加前缀"data-"。添加自定义属性之后可以通过元素的 dataset 属性来访问自定义属性的值。在 dataset 属性中每个自定义属性都会有一个对应的属性,只不过属性名没有前缀"data-"。

插入标记

innerHTML 属性

在读取 innerHTML 属性时,会返回调用它的元素的所有子节点的 HTML 标记。在写入 innerHTML 属性时会覆盖原有的 DOM 树。

但是不同的浏览器的返回值会略有不同,IE 和Opera 中会将所有的标签转换为大写。
使用 innerHTML 属性也有一些限制。大多浏览器中通过 innerHTML 插入的<script>元素中的脚本并不会被执行。

并不是所有元素都支持 innerHTML 属性。不支持 innerHTML 的元素有:<col><colgroup>
<frameset><head><html><style><table><tbody><thead><tfoot><tr>。此
外,在 IE8 及更早版本中,<title>元素也没有 innerHTML 属性。

outerHTML 属性

outerHTML 返回调用它的元素和所有子节点的 HTML 标记。这个属性与 innerHTML 类似,只不过它包含了调用它的元素本身。

insertAdjacentHTML()方法

这个方法也可以插入标记,接受两个参数,插入的位置和要插入的 HTML 文本。第一个参数必须是以下值之一:

内存与性能问题

使用 innerHTML 和outHTML 的方式替换子节点的话会带来一些内存占用的问题。假设某一个元素有一个事件处理程序,在使用这两种方法将这个节点删除后,这个元素与这个事件的绑定关系并不会解除,而是继续留在内存中。因此在使用这两种方法替换节点之前手动删除其事件处理程序以及 JavaScript 对象属性。

使用这两种方法时浏览器会创建一个 HTML 解析器,使用完毕之后会销毁该解析器,创建和销毁 HTML 解析器都会带来性能上的损失,因此要尽量减少赋值的次数。
多次赋值

  1. for (var i=0, len=values.length; i < len; i++){
  2. ul.innerHTML += "<li>" + values[i] + "</li>"; //要避免这种频繁操作!!
  3. }

一次赋值

  1. var itemsHtml = "";
  2. for (var i=0, len=values.length; i < len; i++){
  3. itemsHtml += "<li>" + values[i] + "</li>";
  4. }
  5. ul.innerHTML = itemsHtml;

scrollIntoView()方法

scrollIntoView()方法可以在所有 HTML 元素上调用,通过滚动浏览器窗口或某个容器元素让调用的元素出现在视口中。如果给这个方法传入 true,该元素的顶部与视口顶部平齐,默认为 true。如果传入 false,将使元素底部与视口底部平齐(如果可以的话)。

children 属性

元素的 children 属性是 HTMLCollection 的实例,包含了元素中还是元素的子节点。在 IE8及之前的浏览器中会包含注释节点。

contains()方法

contains()方法传入一个节点,返回一个布尔值,用于确定这个节点是否是调用该方法的节点的后代节点。传入调用元素本身会返回 true。支持该方法的浏览器有 IE、Firefox 9+、Safari、Opera 和 Chrome。

DOM Level 3中的 compareDocumentPosition()方法也可以确定节点间的关系,支持这个方法的浏览器有 IE9+、Firefox、Safari、Opera 9.5+和 Chrome。这个方法返回一个表示关系的位掩码。(调用该方法的节点为参考节点,传入的节点为给定节点。)用返回值与某种节点关系的掩码进行按位与运算就可以知道是否存在这种节点关系。

掩码 节点关系
1 无关(给定节点不在当前文档中)
2 居前(给定节点在参考节点之前)
4 居后(给定节点在参考节点之后)
8 包含(给定节点是参考节点的祖先)
16 被包含(给定节点是参考节点的后代)

插入文本

innerText 属性在读取时返回后代节点中所有的文本节点(包括子节点的子节点),写入的时候会覆盖掉所有后代节点。

支持 innerText 属性的浏览器包括 IE4+、Safari 3+、Opera 8+和 Chrome。Firefox 虽然不支持 innerText,但支持作用类似的 textContent 属性。

  1. function getInnerText(element){
  2. return (typeof element.textContent == "string") ? element.textContent : element.innerText;
  3. }
  4. function setInnerText(element, text){
  5. if (typeof element.textContent == "string"){
  6. element.textContent = text;
  7. } else {
  8. element.innerText = text;
  9. }
  10. }

写入 outerText 会替换掉整个元素。

滚动

scrollIntoViewIfNeeded() 这个方法只在元素在视口中不可见的时候滚动,最终让它可见。接受一个参数,表示是否尽量让元素显示在视口中部。这个方法仅有 Chrome 和 Opera 支持。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注