DOM2 和 DOM3

本章内容:DOM2 和 DOM3 的变化、操作样式和 DOMAPI、DOM遍历与范围

DOM1 级主要定义的是HTML 和 XML 文档的底层结构。DOM2 和 DOM3 级则在这个结构的基础上引入了更多的交互功能,也支持了更高级的XML特性。
DOM2 和 DOM3 的模块

  • DOM2级核心(DOM Level 2 Core):在1级核心基础上构建,为节点添加更多的方法和属性。
  • DOM2级视图(DOM Level 2 Views):为文档定义了基本样式信息不同的视图。
  • DOM2级事件(DOM Level 2 Events):说明了如何使用事件与DOM文档交互。
  • DOM2级样式(DOM Level 2 Style):定义了如何以变成的方式来访问和编辑css样式信息。
  • DOM2级遍历和范围(DOM Level 2 Traversal and Range):引入了遍历DOM文档和选择其特定部分的新接口。
  • DOM2级HTML(DOM Level 2 HTML):在1级HTML基础上后见,添加了更多属性、方法和新接口。

一、DOM变化

DOM2级和3级的目的在于扩展DOM API,满足操作文档的需求,同时提供更好的错误处理及特性检测能力。

为了确定浏览器是否支持这些DOM模块,可以使用 hasFeature() 来检测它们(这个方法在上一章提到过。)

var supportsDOM2Core = document.implementation.hasFeature('Core', '2.0')
var supportsDOM3Core = document.implementation.hasFeature('Core', '3.0')
var supportsDOM2HTML = document.implementation.hasFeature('HTML', '2.0')
var supportsDOM2Views = document.implementation.hasFeature('Views', '2.0')
var supportsDOM2XML = document.implementation.hasFeature('XML', '2.0')

1.1、针对XML 命名空间的变化

有了XML命名空间,不同XML文档的元素就可以混合在一起,共同构成格式良好的文档。HTML不支持XML命名空间,但XHTML支持XML命名空间。以下给出实例中,皆为XHTML文档格式

命名空间要使用xmlns特性来制定,并应将其包含在元素中。


  
    Example XHTML page
  
  
    Hello World
  

在这个例子中,所有的元素都默认被视为XHML 命名空间的元素。要明确地为XML命名空间创建前缀,可以使用xmlns 后跟冒号,再跟前缀。


  
    EX XHTML Page
  
  
    Hello World
  

有时候为了避免不同语言间的冲突,也需要使用命名空间来限定特性。


  
    EX XHTML Page
  
  
    Hello World
  

在只基于一种语言编写XML文档的情况下,命名空间实际上也没有什么用。不过,在混合使用两种语言的情况下,命名空间的用处就非常大了。
比如下面这个混合了 XHML 和 SVG 语言的文档。


  
    Ex XHTML Page
  
  
    
      
    
  

通过设置命名空间,将标识为了与包含文档无关的元素。 所有子元素以及所有的特性,都被认为是 http://www.w3.org/2000/svg 命名空间

1.1.1、Node类型的变化

在 DOM2 级中, Node 类型包含下列特定命名空间的属性。

  • localName: 不带命名空间前缀的节点名称
  • namespaceURL:命名空间 URL 或者(在未指定的情况下是)null。
  • prefix:命名空间前缀或者(在未指定的情况下是)null

当节点使用命名空间前缀时,其nodeName等于 prefix+ ":" + localName。


  
    Ex XHTML Page
  
  
    
      
    
  

以上面这段代码为例。

  • 对 来说
    • localName 和 tagName 是 "html",
    • namespaceURI 是 "http://www.w3.org/1999/xhtml"
    • prefix 是 null
  • 来说
    • localName 是 "svg"
    • tagName 是 "s:svg"
    • namespaceURI 是 "http://www.w3.org/2000/svg"
    • prefix 是 "s"

DOM3 级在此基础上更进一步,又引入了下列与命名空间相关的方法。

  • isDefaultNa mespace(namespaceURI):在指定的 namespaceURI是当前节点的默认命名空间的情况下返回 true。
  • lookupNamespaceURI(prefix):返回给定 prefix 的命名空间。
  • lookupPrefix(namespaceURI):返回给定 namespaceURI的前缀。

针对前面的 代码调用 以上API

console.log(document.body.isDefaultNamespace('http://www.w3.org/1999/xhtml')) // true

var svg = document.getElementsByTagName('s:svg')[0] // 获取 svg的 引用
console.log(svg.lookupPrefix('http://www.w3.org/2000/svg')) // s
console.log(svg.lookupNamespaceURI('s')) // http://www.w3.org/2000/svg
1.1.2、Document 类型的变化

DOM2 级中的 Document 类型 包含下列与命名空间相关的方法:

  • createElementNS(namespaceURI, tagName):使用给定的 tagName 创建一个属于命名空间 namespaceURI 的新元素
  • createAttributeNS(namespaceURI, attributeName):使用给定的 attributeName 创建一个属于命名空间 namespaceURI 的新特性。
  • getElementsByTagNameNS(namespaceURI, tagName):返回属于命名空间 namespaceURI 的tagName 元素的 NodeList
// 创建一个 新的 SVG 元素
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')

// 创建一个属于 某个命名空间 的新特性。
var att = document.createAttributeNS('http://www.somewhere.com', 'radom')

// 取得所有 XHTML 元素
var eles = document.getElementsByTagNameNS('http://www.w3.org/1999/xhml', '*')

只有在文档中存在两个或多个命名空间时,这些与命名空间有关的方法才是必须的。

1.1.3、Element类型

DOM2级核心 中有关Element的变化,主要涉及操作特性。新增的方法如下。

  • getAttributeNS(namespaceURI, localName):取得属于命名空间 namespaceURI 且 名为 localName 的特性
  • getAttributeNodeNS(namespaceURI,localName):取得属于命名空间 namespaceURI 且名为 localName的特性节点。
  • getElementsByTagNameNS(namespaceURI, tagName):返回属于命名空间 namespaceURI 的tagName 元素的 NodeList
  • hasAttributeNS(namespaceURI, localName):确定当前元素是否有一个名为 localName 的特性,而且该特性的命名空间是 namespaceURI。注意:"DOM2 级核心"也增加了一个 hasAttribute() 方法,用于不考虑命名空间的情况。
  • removeAttributeNS(namespaceURI, localName):删除属于命名空间 namespaceURI 且名为 localName 的特性
  • setAttributeNS(namespaceURI, qualifiedName, value):将属于命名空间 namespaceURI 且名为 qualifiedName 的特性 将其值设置为 value
  • setAttributeNodeNS(attNode):设置属于命名空间namespaceURI的特性节点。
    除了第一个参数外,这些方法与 DOM1级中相关方法的作用相同;第一个参数始终都是一个命名空间URI
1.1.4、NamedNodeMap 类型的变化

NameNodeMap 类型也新增了下列与命名空间有关的方法。由于特性是通过 NameNodeMap 表示的,因此这些方法多少情况下只针对特性使用。

  • getNamedItemNS(namespaceURI, localName):取得属于命名空间 namespaceURI 且名为 localName 的项。
  • removeNamedItemNS(namespaceURI, localName):移除属于命名空间 namespaceURI 且民委 localName 的项。
  • setNamedItemNS(node):添加 node,这个节点已经事先指定了 命名空间的信息。

由于一般都是通过 元素 访问特性,所以这些方法很少使用。

1.2、其他方面的变化

这些变化与 XML 命名空间无关,而是更倾向于确保 API 的可靠性及完整性。

1.2.1、DocumentType 类型的变化

DoucmentType 类型新增了 3个属性:publicIdststemIdinternalSubset。前两个属性表示的是文档类型声明中的两个信息段。


console.log(document.doctype.publicId) // -//W3C/DTD HTML 4.01//EN
console.log(document.doctype.systemId) // http://www.w3.org/TR/html4/strict.dtd

internalSubset 用于访问包含在文档类型中的额外定义。在HTML中极少用到,在XML中常用一些。

1.2.2、Document 类型的变化

Document类型变化中唯一于 命名空间无关的方法是 importNode()这个方法的用途是从一个文档中取得一个节点,然后将其导入到另一个文档,使其成为这个这个文档的一部分。需要注意的是,每个节点都有一个 ownerDocument 属性,表示所属文档。如果调 appendChild() 是传入的节点属于 不同文档(ownerDocument的值不一样),则会导致错误。在调用 importNode()时传入不同文档的节点则会返回一个新节点,这个新节点的所有权归当前文档所有。
importNode() 方法和 cloneNode() 方法非常相似,接受两个参数:要复制的节点、是否复制子节点,返回原来节点的副本。

var newNode = document.importNode(oldNode, true) // 深复制,复制子节点
document.body.appendChild(newNode)

同样这个方法在HTML中并不常用,在XML中使用较多。


“DOM2级视图” 模块添加了一个 名为 defaultView 的属性,其中保存着一个指针,指向拥有给定文档窗口(或框架)。IE不支持此属性,IE中 的等价属性时 prentWIndow(Opera也支持这个属性)。
确定文档的归属窗口

var parentWindow = document.defaultView || document.parentWindow

"DOM2级核心" 还为 docunebt.implementation 对象规定了两个新方法:

  • createDocumentType(): 用于创建一个 新的 DocumentType 节点,接 受以下参数:
    • 文档类型名称
    • publicId
    • systemId
var doctype = document.implementation.createDocumentType('html', '-//W3C/DTD HTML 4.01//EN', 'http://www.w3.org/TR/html4/strict.dtd')

由于既有文档类型不能改变,因此这个方法只在创建新文档时有用

  • createDocument():用于创建一个新文档,接受三个参数:
  • 针对文档元素的 namespaceURI
  • 文档元素的标签名
  • 文档类型
// 创建一个新的XML文档
var xmlDoc = document.implementation.createDocument('', 'root', null)

// 创建一个XHML 文档
// 这里的 doctype 引用 上面例子中 通过 createDocumentType创建的
var xhtmlDoc = document.implementation.createDocument('http://www.w3.org/1999//xhtml', 'html', doctype)

"DOM2级HTML" 模块 页为 document.implementation 新增了一个方法,createHTMLDocument(),改方法创建一个完整的 HTML 文档。接受一个参数:即新创建文档的标题(中间的文本)。</p> <pre><code class="js">var htmlDoc = document.implementation.createHTMLDocument('New Doc') </code></pre> <p><code>通过 createHTMLDocument() 创建的这个文档,是HTMLDocument类型的实例,具有该类型的所有属性和方法包括 title 和 body 属性。 这个方法存在兼容问题</code></p> <h5>1.2.3、Node类型的变化</h5> <p>添加了 <strong>isSupported()</strong> 方法。与 DOM1级的 hasFeature() 方法类似。isSupported() 方法用于确定当前节点具有什么能力。<code>接受两个参数:特性名 和 特性版本号;返回一个布尔值。</code></p> <pre><code class="js">if (document.body.isSupported('HTML', '2.0')) { // todo } </code></pre> <p><code>与 hasFeature() 类似,建议在 确定某个特性是否可用时,最好还是使用能力检测</code></p> <hr> <p>DOM3级 引入了 两个辅助比较节点的方法:isSameNode() 和 isEqualNode()。这两个方法都接受一个节点参数,</p> <ul> <li> <strong>isSameNod()</strong>:传入节点与引用节点<strong>相同时</strong>(两个节点引用的是同一个对象)返回 true。</li> <li> <strong>isEqualNode()</strong>:传入节点与引用节点<strong>相等时</strong>(相同的类型,具有相等的属性,并且 attributes 和 childNodes 也相等)返回true</li> </ul> <pre><code class="js">var div1 = document.createElement('div') div.setAttribute('class', 'box') var div2 = document.createElement('div') dvi2.setAttribute('class', 'box') console.log(div1.isSameNode(div1)) // true console.log(div1.isEqualNode(div2)) // true // 引用的不是同一个对象,不相同 console.log(div1.isSameNode(div2)) // false </code></pre> <h5>1.2.4、框架的变化</h5> <p>DOM2级中有一个新属性:<strong>contentDocument</strong>,这个属性包含一个指针,指向表示框架内容的文档对象。IE8之前不支持 这个属性。但支持一个 <strong>contentWindow</strong> 的属性,该属性返回框架的 window 对象,而这个window 对象又有一个 document 属性。</p> <pre><code class="js">// 访问内嵌框架的文档对象 var iframe = document.getElementById('myIframe') var iframeDoc = iframe.contentDocument || iframe.contentWindow.document </code></pre> <p><code>所有浏览器都支持 contentWindow属性</code></p> <h3>二、样式</h3> <p>"DOM2级样式"围绕样式机制提供了一套API。可以通过 hasFeature() 检测是否支持。</p> <pre><code class="js">var supportsDOM2CSS = document.implementation.hasFeature('CSS', '2.0') var supportsDOM2CSS2 = document.implementation.hasFeature('CSS2', '2.0') </code></pre> <h4>2.1、访问元素的样式</h4> <p>任何支持style 特性的 HTML 元素在 JavaScript中都有对应的 style 属性。这个 style 对象是 <strong>CSSStyleDeclaration</strong> 的实例。包含HTML的style 特性指定的所有样式信息。<br> <code>css 中的 '-' 在JavaScript中要变成 驼峰式,比如:background-color = backgroundColor</code></p> <pre><code class="js">var myDiv = document.getElementById('div') // 设置背景颜色 myDive.style.backgroundColor = 'cyan' // 改变大小 myDiv.style.width = '200px' // 指定边框 myDiv.style.border = '1px solid black' </code></pre> <p>同时通过 style 对象也可以获取 style特性中指定的 样式</p> <pre><code class="js">// 获取背景色 console.log(myDiv.style.backgroundColor) </code></pre> <h5>2.1.1、DOM样式属性和方法</h5> <p>"DOM2级样式"规范还未 style 对象定义了一些属性和方法。</p> <ul> <li> <strong>cssText</strong>:能够访问到 style 特性中的 css代码</li> <li> <strong>length</strong>:应用元素的CSS属性的数量</li> <li> <strong>parentRule</strong>:表示CSS信息的CSSRule对象</li> <li> <strong>getPropertyPriority(propertyName)</strong>:如果给定的属性使用了 !important 设置,则返回 'important';否则,返回空字符串</li> <li> <strong>getPropertyValue(propertyName)</strong>:返回给定属性的字符串值。</li> <li>item(index):返回给定位置的CSS属性的名称。</li> <li> <strong>removeProperty(propertyName)</strong>:从样式中删除给定属性</li> <li> <strong>setProperty(propertyName, value, priority)</strong>:将给定属性设置为相应的值,并加上优先权标志('important'或一个空字符串)。</li> </ul> <p><code>通过 cssText属性可以访问style 特性中的代码。并且如果通过 cssText 修改 特性,会重写整个 style 特性的值。</code></p> <pre><code class="js">// 设置 myDiv.style.cssText = 'width: 24px; height: 30px' // 获取 console.log(myDive.style.cssText) </code></pre> <p><strong>length属性 与 item()方法配套使用</strong>,以便在迭代元素中定义的css属性,在使用length 和 item() 时,style 对象实际上就相当于一个集合,可以使用方括号语法来代替item()</p> <pre><code class="js">for (var i = 0, len = myDiv.style.length; i < len; i++) { console.log(myDiv.style[i]) // myDiv.style.item(i) } </code></pre> <p>通过如上遍历可以取得所有的特性名,然后通过 <strong>getPropertyValue()</strong> 获取获取每一个特性值</p> <pre><code class="js">var prop, value, i, len for(i = 0, len = myDiv.length; i < len; i++) { prop = myDiv.style.item(i) value = myDiv.style.getPropertyValue(prop) console.log(prop + ": " + value ) } </code></pre> <p><code>getPropertyValue() 返回的始终是CSS属性值的字符串表示。</code><br> 使用<strong>getPropertyCSSValue()</strong>方法,返回一个对象。这个对象又两个属性:</p> <ul> <li>cssText<br> 这个属性的值与 getPropertyValue() 返回的值相同</li> <li>cssValueType<br> 返回一个数值常量: <ul> <li>0:表示继承的值</li> <li>1:表示基本的值</li> <li>2:表示值列表</li> <li>3:表示自定义的值</li> </ul> </li> </ul> <pre><code class="js">var i, prop, value, len for(i = 0, len = myDiv.length; i < len; i++) { prop = myDiv.style.item(i) value = myDiv.style.getPropertyCSSValue(prop) // 获取 CSSValue 对象 console.log(prop + ': ' + value.cssText + '(' + value.cssValueType + ')') } </code></pre> <p>要从元素的样式中移除某个 CSS 属性,需要使用 <strong>removePropertyValue()</strong> 方法。这个方法移除一个属性</p> <pre><code class="js">myDiv.style.removeProperty('border') </code></pre> <h5>2.1.2、计算的样式</h5> <p>"DOM2级样式"增强了 document.defaultView,提供了 <strong>getComputedStyle()</strong> 方法。这个方法接受两个参数:要取得计算样式的元素、一个伪元素字符串(例如 :after)如果不需要伪元素可以设置为 null。 返回一个 CSSStyleDeclaration 对象。</p> <pre><code class="html"><html> <head> <title>EX

var myDiv = document.getElementById('div')
var computedStyle = document.defaulltView.getComputedStyle(myDiv, null)
console.log(computedStyle .color) // rgb(255, 192, 203)
console.log(computedStyle .width) // 20px
console.log(computedStyle .height) // 30px

IE不支持 getComputedStyle() 方法。 在IE中,每个具有 style 属性的元素还有一个 currentStyle 属性。这个属性是CSSStyleDeclaration的实例,包含当前元素全部计算后的样式。

var computedStyle = myDiv.currentStyle

console.log(computedStyle.width) // 20px

在所有浏览器中,所有计算后的样式都是只读的;不能修改计算和样式对象中的css属性。

2.2、操作样式表

CSSStyleSheet类型表示的是样式表,是一套只读的接口,CSSStyleSheet 继承自 StyleSheet,从 StyleSheet接口继承而来的属性如下。

  • disabled: 表示样式表是否被禁用的布尔值。这个属性是 可读/写的,将这个属性设置为 true,从以禁用样式表。
  • href:如果样式表是通过包含的,则是样式表的URL;否则,是null
  • media:当前样式表支持的所有媒体类型的集合。与所有 DOM 集合一样,这个集合也有一个length 属性和 一个 item() 方法。也可以使用方括号语法取得集合中特定的项。如果集合是空列表,表示样式表适用于所有媒体。在IE中,meida是一个反映