JavaScript DOM2和DOM3扩展

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>JavaScript DOM2和DOM3扩展</title>
<link rel="stylesheet" href="./assets/transitions.css">
</head>

<body>
<script type="text/javascript">
// 立即执行函数
(function () {
// 严格模式
"use strict";
// DOM的变化
// DOM2级和3级的目的在于扩展DOM API,以满足操作XML的所有需求,同事提供更好的错误处理及特性检测能力。从某种意义上来讲,实现这一目的的很大程度意味着对命名空间的支持

// 针对XML命名空间的变化

// 1.Node类型的变化

// 在DOM2级中,Node类型包含下列特定于命名空间的属性:
// localName - 不带命名空间前缀的节点名称
// namespaceURI - 命名空间URI或者(在未指定的情况下是)null
// prefix - 命名空间前缀或者(在未指定的情况下是)null

// DOM3级在此基础上更进一步,又引入了下列与命名空间有关的方法:
// isDefaultNamespace(namespace: DOMString) - 在指定的namespaceURI是当前节点的默认命名空间的情况下返回true
// lookupNamespaceURI(prefix: DOMString) - 返回给定prefix的命名空间
// lookupPrefix(namespace: DOMString) - 返回给定 namespaceURI的前缀

// 2.Document类型的变化

// DOM2级中的Document类型也发生了变化,包含下列命名空间有关的方法:
// createElementNS(namespace: DOMString, qualifiedName: DOMString) - 使用给定的 tagName 创建一个属于命名空间 namespaceURI 的新元素
// createAttributeNS(namespaceURI, attributName) - 使用给定的attributName 创建一个属于命名空间 namespaceURI的新元素
// getElementsByTagNameNS(namespace: DOMString, localName: DOMString) - 返回属于命名空间 namespaceURI 的 tagName 元素的 NodeList

// 3.Element类型的变化

// DOM2级核心中有关Element的变化,主要涉及操作特性,新增的方法如下:
// getAttributeNS(namespace: DOMString, localName: DOMString) - 取得属于命名空间 namespaceURI 且名为 localName 的特性
// getAttributeNodeNS(namespaceURI, tagName) - 返回属于命名空间 namespaceURI 且名为 localName 的特性
// getElementsByTagNameNS(namespace: DOMString, localName: DOMString) - 返回属于命名空间 namespaceURI 的 tagName 元素的 NodeList
// hasAttributeNS(namespace: DOMString, localName: DOMString) - 确定当前元素是否有一个名为 localName 的特性,而且该特性的命名空间是 namespaceURI。
// removeAttributeNS(namespace: DOMString, localName: DOMString) - 删除属于命名空间 namespaceURI 且名为 localName 的特性。
// setAttributeNS(namespace: DOMString, name: DOMString, value: DOMString) - 设置属于命名空间 namespaceURI 且名为 qualifiedName 的特性的值为 value。
// setAttributeNodeNs(attNode) - 设置属于命名空间 namespaceURI的特性节点。

// 4.NamedNodeMap类型的变化

// NamedNodeMap类型也新增了下列与命名空间有关的方法。由于特性是通过NamedNodeMap表示的,因此这些方法多数情况下只针对特性使用。
// getNamedItemNS(namespaceURI, localName) - 取得属于命名空间 namespaceURI 且名为 localName 的项
// removeNamedItemNS(namespaceURI, localName) - 移出属于命名空间 namespaceURI 且名为 localName 的项。
// setNamedItemNS(node) - 添加node,这个节点已经实现指定了命名空间信息。

// 其他方面的变化

// 1.DocumentType 类型的变化

// DocumentType 类型新增了3个属性:publicId、systemId 和 internalSubset。其中,前两个属性表示的是文档类型声明中的两个信息段,这两个信息段在DOM1级中是没有办法访问到的。

// 2.Document 类型的变化

// Document类型的变化中唯一与命名空间无关的方法是importNode()。这个方法的用途是从一个文档中取得一个节点,然后将其导入到另一个文档,使其成为这个文档结构的一部分。需要注意的是,每个节点都有一个ownerDocument属性,表示所属的文档。
// 如果调用appendChild()时传入的节点属于不同的文档(ownerDocument属性的值不一样),则会导致错误。
// 但在调用importNode()时传入不同文档的节点则会返回一个新节点,这个新节点的所有权归当前文档所有。

// importNode()方法与Element与cloneNode()方法非常相似,它接受两个参数:要复制的节点和一个表示是否复制子节点的布尔值。返回的结果是原来节点的副本,但能够在当前文档中使用。

// var newNode = document.importNode(oldNode, true) //导入节点机器所有子节点
// document.body.appendChild(newNode)

// DOM2级视图模块添加了一个名为defaultView的属性,其中保存着一个指针,指向拥有给定文档的窗口(或框架)。

// var parentWindow = document.defaultView || document.parentWindow;

// DOM2级核心为document.implementation对象规定了两个新方法:createDocumentType() 和 createDocument()。前者用于创建一个新的DocumentType节点,接收3个参数:文档类型名称、publicId、systemId。

// createDocumentType()只在创建新文档时有用:创建新文档时需要用到createDocument()方法。这个方法接受3个参数:针对文档中元素的namespaceURI、文档元素的标签名、新文档的文档类型。

// var doctype = document.implementation.createDocumentType("html","-//W3C//DTD XHTML 1.0 Strict//EN", "http://www.w3.org/TR/xhtml/DTD/xhtml-strict.dtd");

// var doc = document.implementation.createDocument("http://www.w3.org/1999/xhtml","html",doctype);

// DOM2级HTML模块也为document.implementation新增了一个方法,名叫createHTMLdocument()。这个方法用途是创建一个完整的HTML文档,包括<html>、<head>、<title>和<body>元素。这个方法只接受一个参数,即新创建文档的标题(放在<title>元素中的字符串),返回新的HTML文档。

// var htmldoc = document.implementation.createHTMLDocument("New Doc");
// console.log(htmldoc.title);
// console.log(typeof htmldoc.body);

// 3.Node类型的变化
// Node类型中唯一与命名空间无关的变化,及时添加了isSupported()方法。用于确定当前节点具有什么能力。

// if(document.body.isSupported("html", "2.0")){
// 执行只有“DOM2 级HTML”才支持的操作
// }

// DOM3级引入了两个辅助比较节点的方法 isSameNode() 和isEqualNode()。这两个方法都接收一个节点参数,并在窜入节点与引用的节点相同或相等时返回true。所谓相同,指的是两个节点引用的是同一个对象。

// var div1 = document.createElement('div');
// div1.setAttribute('class','box');

// var div2 = document.createElement('div');
// div2.setAttribute('class', 'box');

// console.log(div1.isSameNode(div2));
// console.log(div1.isEqualNode(div2));
// console.log(div1.isSameNode(div2));

// DOM3级还针对DOM节点添加额外数据引入了新方法。其中,setUserData() 方法会将数据指定节点,它接受3个参数:要设置的键、实际的数据(可以是任何数据类型)和处理函数。一下代码可以将数据指定给一个节点。

// document.body.setUserData("name","Nicholas",function(){});

// var value = document.body.getUserData("name");

// 传入 setUserData()中的处理函数会在带有数据的节点被复制、删除、重命名或引入一个文档时调用,因而你可以实现决定在上述操作发生时如何处理用户数据。处理函数接受5个参数:表示操作类型的数值(1 - 表示复制 2 - 表示导入 3 - 表示删除 4 - 表示重命名)、数据键、数据值、源节点和目标节点。再删除节点时,源节点null;复制节点时,目标节点时null。

// var div = document.createElement('div');
// div.setUserData('name','Nicholas',function(operation,key,value,src,dest){
// if(operation === 1){
// dest.setUserData(key,value,function(){});
// }
// });

// var newDiv = div.cloneNode(true);
// console.log(newDiv.getUserData('name'));

// 4.框架的变化
// 框架和内嵌框架分别用HTMLFrameElement和HTMLFrameElement表示,它们在DOM2级中都有了一个新属性,名叫contentDocument。这个属性包含一个指针,指向表示框架内容的文档对象。

// var iframe = document.getElementById('myIframe');
// var iframeDoc = iframe.contentDocument; // 在IE8以前的版本中无效

// IE8之前支持的一个属性contentWindow的属性。改属性返回框架的window对象,而这个window对象又有一个document属性。因此,要向在上述所有浏览器汇总访问内嵌框架的文档对象

// var iframe = document.getElementById('myIframe');
// var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;

// 样式

// 访问元素的样式
// css属性 —— javascript属性
// background-image style.backgroundImage
// color style.color
// display style.display
// font-family style.fontFamily

// 1.DOM样式属性和方法

// DOM2级样式规范还未style对象定义了一些属性和方法。
// cssText: 通过它能够访问到style特性中的CSS代码。
// length: 应用给元素的CSS属性的数量
// parentRule: 表示CSS信息CSSRule对象。
// getPropertyCSSValue(propertyName): 返回包含给定属性值的CSSValu对象。
// getProperPriority(propertyName): 如果给定属性使用了!important设置,则返回“important”,否则返回空字符串。
// getPropertyValue(propertyName): 返回给定属性的字符串值。
// item(index): 返回给定位置的CSS属性的名称。
// removeProperty(propertyName): 从样式中删除给定属性。
// setProperty(propertyName,value,priority): 将给定属性设置为相应的值,并加上优化权标志(“important”或者一个空字符串)。

// 2.计算的样式

// DOM2级样式增强了document.defaultView,提供了getComputedStyle()方法。这个方法接受两个参数:要取得计算样式的元素和一个微元素字符串(例如:“:after”).如果不需要伪元素信息,第二个参数可以是null。getComputedStyle()方法返回一个CSSStyleDeclaration对象(与style属性的类型相同),其中包含当前元素的所有计算的样式。

// 操作样式表

// CSSStyleSheet类型表示的是样式表,报错通过<link>元素包含的样式表在<sytle>元素中定义的样式表。从StyleSheet接口继承而来的属性如下:
// disabled: 表示样式表是否被禁用的布尔值。
// href:如果样式表示通过<link>包含的,则样式表的URL,否则,是NULL。
// media:当前样式表支持的所有媒体类型的集合。
// ownerNode:指向拥有当前样式表的节点的指针。样式表可能在HTML通过<link>或<style/>引入的(在XML中可能是通过处理指令引入的)。如果当前样式表是其他样式表通过@import导入的情况下,这个属性值为null。
// parentStyleSheet:在当前样式表是通过@import导入的情况下,这个属性是一个指向导入他的样式表的指针。
// title:ownerNode中title属性的值。
// type:表示样式表类型的字符串。
// cssRule:如果样式表是通过@import导入的,这个属性就是一个指针,指向表示导入的规则;否则,值为null。
// deleteRule(index):删除cssRules集合中指定的位置插入rule字符串。
// insertRule(rule, index):向cssRules集合中指定的位置插入rule字符串。

// 1.CSS规则

// cssText:返回整条规则对应的文本。
// parentRule:如果当前规则是导入的规则,这个属性应用就是导入规则;否则,这个值为null。
// parentStyleSheet:当前规则所属的样式表。
// selectorText:返回当前规则的选择符文本。
// style:一个CSSStyleDeclaration对象,可以通过它设置或取得规则中特性的样式值。
// type: 表示规则类型的常量值。

// 2.创建规则
// insertRule()方法。这个方法接受两个参数:规则文本和表示在哪里插入规则的索引。

// 3.删除规则
// deleteRule()方法,这个方法接受一个参数:要删除的规则的位置。


// 元素大小

// 1.偏移量 - 包括元素在屏幕上占用的所有可见的空间。元素的可见大小由其高度、宽度决定,包括所有内边距、滚动条和边框大小(注意:不包括外边距)。有4个属性可以取得元素偏移量:
// offsetHeight:元素在垂直方向上占用的空间大小,以像素计。
// offsetWidth:元素在水平方向上占用的空间大小,以像素计。
// offsetLeft:元素左外边框至包含元素的左内边距之间的像素距离。
// offsetRight:元素上外边框至包含元素的上内边框之间的像素距离。

// 2.客户区大小 - 元素内容及其内边距所占据的空间大小。
// clientWidth:元素内容区宽度加上左右边距宽度。
// clientHeight:元素内容区高度加上上下内边距高度。

// 3.滚动大小 - 包含滚动内容的元素大小。
// scrollHeight:在没有滚动条的情况下,元素内容的总高度。
// scrollWidth:在没有滚动条的情况下,元素内容的总宽度。
// scrollLeft:被隐藏在内容区域左侧的像素数。通过设置这个属性可以改变元素的滚动位置。
// scrollTop: 被隐藏在内容区域上方的像素数。通过设置这个属性可以改变元素的滚动位置。

// 4.确定元素大小
// getBoundingClientRect()方法。这个方法返回一个矩形对象,包含4个属性:left、top、right和bottom。

// 遍历
// DOM2级遍历和范围模块定义了两个用于辅助完成顺序遍历DOM结构的类型:NodeIterator和TreeWalker。这两个类型能够基于给定的起点对DOM结构执行深度优化的遍历操作。

// 检测浏览器对DOM2级遍历能力的支持情况
// var supportsTraversale = document.implementation.hasFocus("Traversal", '2.0');
// var supportsNodeIterator = (typeof document.createNodeIterator === "function");
// var supportaTreeWalker = (typeof document.createTreeWalker === "function")

// createNodeIterator(root: Node, whatToShow?: unsigned long, filter?: NodeFilter)
// 这个方法接受下列4个参数:

// root:想要座位搜索起点的树中的节点。
// whatToShow:表示要访问哪些节点的数字代码。
// filter:是一个NodeFilter对象,或者一个表示应该接受还是拒绝谋众特定节点的函数。
// entityReferenceExpansion:布尔值,便是是否要扩展实体引用。这个参数在HTML页面中没有用,因为其中的实体引用不能扩展。

// whatToShow参数是一个位掩码,通过应用一个或多个过滤器(filter)来确定要访问哪些节点。这个参数与的值以常量形式在NodeFilter类型中定义,如下所示:
// NodeFilter.SHOW_All:显示所有类型的节点。
// NodeFilter.SHOW_ELEMENT:显示元素节点。
// NodeFilter.SHOW_ATTRIBUTE:显示特性节点。
// NodeFilter.SHOW_TEXT:显示文本节点。
// NodeFilter.SHOW_CDATA_SECTION:显示CDAT节点。对HTML页面没有用。
// NodeFilter.SHOW_ENTITY_REFERENCE:显示实体引用节点。对HTML页面没有用。
// NodeFilter.SHOW_ENTITYE:显示实体节点。对HTML页面没有用。
// NodeFilter.SHOW_PROCESSING_INSTRUCTION:显示处理指令节点。对HTML页面没有用。
// NodeFilter.SHOW_COMMENT:显示注释节点。
// NodeFilter.SHOW_DOCUMENT:显示文档节点。
// NodeFilter.SHOW_DOCUMENT_TYPE:显示文档类型的节点。
// NodeFilter.SHOW_DOCUMENT_FRAGMENT:显示文档片段的节点。对HTML页面没有用。
// NodeFilter.SHOW_NOTATION:显示符合节点。对HTML页面没有用。

// TreeWalker,是NodeIterator的一个更高级的版本。除了包括nextNode()和previousNode()在内的相同的功能之外,这个类型还提供了下列用于在不同方向上遍历DOM结构的方法。

// parentNode():遍历当前节点的父节点。
// firstChild():遍历当前节点的第一个子节点。
// lastChild():遍历当前节点的最后一个子节点。
// nextSibling():遍历当前节点的下一个同辈节点。
// previousSibling():遍历当前节点的上一个同辈节点。

// 创建TreeWalker对象要使用document.createTreeWalker(root: Node, whatToShow?: unsigned long, filter?: NodeFilter)方法,这个方法接受4个参数与document.createNodeIterator(root: Node, whatToShow?: unsigned long, filter?: NodeFilter)方法相同:
// 作为遍历起点的根节点、要显示的节点类型、过滤器和一个表示是否扩展实体引用的布尔值。

// var div = document.getElementById('div1');
// var filter = function(node){
// return node.tagName.toLowerCase() === "li" ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
// };

// var walker = document.createTreeWalker(div, NodeFilter.SHOW_ELEMENT, filter, false);

// var node = iterator,nextNode();
// while(node !== null){
// console.log(node.tagName); // 输出标签名
// node = iterator.nextNode();
// }

// 范围,DOM2级遍历和范围模块定义了范围接口。

// DOM中的范围
// DOM2级在Document类型中定义了createRange()方法。每个范围由一个Range类型的实例来表示,这个实例拥有很多属性和方法:
// startContainer:包含范围起点的节点(即选区中第一个节点的父节点)
// startOffset:范围在startContainer中起点的偏移量。如果startContainer是文本节点、注释节点或CDATA节点,那么startOffset就是范围起点之前跳过的字符数量。否则startOffset就是范围中第一个子节点的索引。
// endContainer:包含范围重点的节点(即选区中最后一个节点的父节点)
// endOffset:范围在endContainer中终点的偏移量(与startOffset遵循相同的取值规则)。
// commonAncestorContainer:startContainer和endContainer共同的祖先节点在文档树中位置最深的那个。
// setStartBefore(refNode):将范围的起点设置在refNode之前,因此refNode也就是范围选区中的第一个子节点。同事会将startContainer属性设置为refNode.parentNode,将startOffset属性设置为refNode在其父节点的childNodes集合中的索引。
// setStartAfter(refNode):将范围的起点设置在refNode之后,因此refNode也就不再范围之内了,其下一个同辈节点才是范围选区中的第一个子节点。同时会将startContainer属性设置为refNode.parentNode,将startOffset属性设置为refNode在其父节点的childNodes集合中的索引加1.
// setEndBefore(refNode):将范围的重点设置在refNode之前,因此refNode也就不再范围之内了,其上一个同辈节点才是范围选区中的最后一个子节点。同时会将endContainer属性设置为refNode.parentNode,将endOffset属性设置为refNode再其父节点的childNodes集合中的索引。
// setEndAfter(refNode):将范围的重点设置在refNode之后,因此refNode也就是范围选区中的最后一个子节点。同时会将endCOntainer属性设置为refNode.parentNode,将endOffset属性设置为refNode在其父节点的childNode集合中的索引加1.

// 1.用DOM范围实现简单选择

// <!DOCTYPE html>
// <html>
// <head>
// <meta charset="utf-8">
// <meta http-equiv="X-UA-Compatible" content="IE=edge">
// <title></title>
// <link rel="stylesheet" href="">
// </head>
// <body>
// <p id="p1">
// <b>Hello</b> world!
// </p>
// </body>
// </html>

// var range1 = document.createRange();
// range2 = document.createRange();
// p1 = document.getElementById('p1');

// range1.selectNode(p1);
// range2.selectNodeContents(p1);

// 2.用DOM范围实现复杂选择
// 要创建复杂的范围就得使用setStart()和setEnd()方法。这两个方位都接受两个参数:一个参展节点和一个偏移量。

// 3.操作DOM范围中的内容
// deleteContents(),这个方法能够从文档中删除范围所包含的内容。
// extractContents(),也会从文档中移出范围选区。会返回范围的文档片段。
// cloneContents(),创建范围对象的一个副本,然后在文档的其他地方插入该副本。返回范围中节点的副本。

// 4.插入DOM范围中的内容
// insertNode()可以向范围选区的开始处插入一个节点。
// surroundContents(newParent: Node),环绕范围插入节点,这个方法接受一个参数,即环绕范围内容的节点。

// 5.折叠DOM范围
// collapse()方法来折叠范围,这个方法接受一个参数,一个布尔值,表示要折叠刀范围的哪一端。

// 6.比较DOM范围
// compareBoundaryPoints(how: unsigned short, sourceRange: Range) 方法来确定这些范围是否有公共的边界(起点或重点)。这个方法接受两个采纳数:表示比较方式的常量值和要比较的范围。

// 7.复制DOM范围
// cloneRange()

// 8.清理DOM范围
// 在使用完范围之后,最好是调用detach()方法,以便从创建范围的文档中分离出该范围。

// range1.detach(); // 从文档中分离
// range1 = null; // 解除引用

// IE8及更早版本中的范围
})()
</script>
</body>

</html>