JS高级程序设计——第12章 DOM2和DOM3 12.1 DOM变化

一、DOM变化

  1. DOM1 级主要定义的是 HTML 和 XML 文档的底层结构

    DOM2 和 DOM3 级则在这个结构的基础上引入了更多的交互能力,也支持了更高级的 XML 特性

  2. DOM2 和 DOM3 级分为许多模块(模块之间具有某种关联),分别描述了 DOM 的某个非常具体的子集。这些模块如下。

     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 基础上构建,添加了更多属性、方法和新接口。

本章探讨除“DOM2 级事件”之外的所有模块,“DOM2 级事件”模块将在第 13 章进行全面讲解

DOM3 级又增加了“XPath”模块和“加载与保存”(Load and Save)模块。这 些模块将在第 18 章讨论。

  1. DOM2 级和 3 级的目的在于扩展 DOM API,以满足操作 XML 的所有需求,同时提供更好的错误处 理及特性检测能力。从某种意义上讲,实现这一目的很大程度意味着对命名空间的支持。
  2. 可以通过下列代码来确定浏览器是否支持这些 DOM 模块

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

1、XML命名空间
  1. 有了 XML 命名空间,不同 XML 文档的元素就可以混合在一起,共同构成格式良好的文档,而不必担心发生命名冲突。从技术上说,HTML 不支持 XML 命名空间,但 XHTML 支持 XML 命名空间。 因此,本节给出的都是 XHTML 的示例。
  2. 命名空间要使用 xmlns 特性来指定XHTML 的命名空间是 http://www.w3.org/1999/xhtml,在任何格式良好 XHTML 页面中,都应该将其包含在<html>元素中,如下面的例子所示。
<html xmlns="http://www.w3.org/1999/xhtml">
   <head>
      <title>Example XHTML page</title>
   </head>
   <body>
      Hello world!
   </body>
</html>

对这个例子而言,其中的所有元素默认都被视为 XHTML 命名空间中的元素。

  • 要想明确地为 XML 命名空间创建前缀,可以使用 xmlns 后跟冒号,再后跟前缀,如下所示。
<xhtml:html xmlns:xhtml="http://www.w3.org/1999/xhtml">
        <xhtml:head>
            <xhtml:title>Example XHTML page</xhtml:title>
        </xhtml:head>
        <xhtml:body>
            Hello world!
        </xhtml:body>
</xhtml:html>

这里为 XHTML 的命名空间定义了一个名为 xhtml 的前缀,并要求所有 XHTML 元素都以该前缀开头。

  • 具体xml命名空间示例参考:https://www.runoob.com/xml/xml-namespaces.html

  • 有时候为了避免不同语言间的冲突,也需要使用命名空间来限定特性,如下面的例子所示。这个例子中的特性 class 带有一个 xhtml 前缀
    在这里插入图片描述

  • 在只基于一种语言编写 XML 文档的情况下,命名空间实际上也没有什么用。不过,在混合使用两种语言的情况下,命名空间的用处就非常大了。来看一看下面这个混合了 XHTML 和 SVG 语言的文档:
    在这里插入图片描述

    在这个例子中,通过设置命名空间,<svg>标识为了与包含文档无关的元素。此时,<svg>元素的所有子元素,以及这些元素的所有特性,都被认为属于 http://www.w3.org/2000/svg 命名空间。即 使这个文档从技术上说是一个 XHTML 文档,但因为有了命名空间,其中的 SVG 代码也仍然是有效的。

2、 Node类型的变化
  1. DOM2 级中,Node 类型包含下列特定于命名空间的属性
     prefix:命名空间前缀或者(在未指定的情况下是)null。
     localName:不带命名空间前缀的节点名称。
     namespaceURI:命名空间 URI 或者(在未指定的情况下是)null。
    当节点使用了命名空间前缀时,其 nodeName 等于 prefix+":"+ localName。以下面的文档为例:
    在这里插入图片描述
    对于<html>元素来说,它的 localName 和 tagName 是"html",namespaceURI 是"http://www. w3.org/1999/xhtml",而 prefix 是 null;
    对于<s:svg>元素而言,它的 localName 是"svg", tagName 是"s:svg",namespaceURI 是"http://www.w3.org/2000/svg",而 prefix 是"s"。

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

    针对前面的例子,可以执行下列代码:

alert(document.body.isDefaultNamespace("http://www.w3.org/1999/xhtml"); //true
//假设 svg 中包含着对<s:svg>的引用 
alert(svg.lookupPrefix("http://www.w3.org/2000/svg")); //"s" 
alert(svg.lookupNamespaceURI("s")); //"http://www.w3.org/2000/svg"
3、Document类型的变化
  1. DOM2 级中的 Document 类型也发生了变化,包含了下列与命名空间有关的方法。
     createElementNS(namespaceURI, tagName):使用给定的 tagName 创建一个属于命名空间 namespaceURI 的新元素
     createAttributeNS(namespaceURI, attributeName):使用给定的 attributeName 创建一个属于命名空间 namespaceURI 的新特性
     getElementsByTagNameNS(namespaceURI, tagName)返回属于命名空间 namespaceURI 的 tagName 元素的 NodeList
  • 使用这些方法时需要传入表示命名空间的 URI(而不是命名空间前缀),如下面的例子所示:
//创建一个新的 SVG 元素
var svg = document.createElementNS("http://www.w3.org/2000/svg","svg");
//创建一个属于某个命名空间的新特性
var att = document.createAttributeNS("http://www.somewhere.com", "random");
//取得所有 XHTML 元素
var elems = document.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "*");
4、Element 类型的变化

DOM2 级核心”中有关 Element 的变化,主要涉及操作特性。新增的方法如下:
在这里插入图片描述除了第一个参数之外,这些方法与 DOM1 级中相关方法的作用相同;第一个参数始终都是一个命名空间 URI

4、 NamedNodeMap 类型的变化(很少使用)

NamedNodeMap 类型也新增了下列与命名空间有关的方法。由于特性是通过 NamedNodeMap 表示的,因此这些方法多数情况下只针对特性使用
 getNamedItemNS(namespaceURI,localName)取得属于命名空间 namespaceURI 且名为localName 的
 removeNamedItemNS(namespaceURI,localName)移除属于命名空间 namespaceURI 且名为 localName 的项。
 setNamedItemNS(node)添加 node,这个节点已经事先指定了命名空间信息。
由于一般都是通过元素访问特性,所以这些方法很少使用

三、其他方面的变化

DOM 的其他部分在“DOM2 级核心”中也发生了一些变化。这些变化与 XML 命名空间无关,而是更倾向于确保 API 的可靠性及完整性

1、DocumentType 类型的变化
  1. DocumentType 类型新增了 3 个属性publicIdsystemIdinternalSubset。其中,前两个属性表示的是文档类型声明中的两个信息段,这两个信息段在 DOM1 级中是没有办法访问到的。
  • 以下面的 HTML 文档类型声明为例。
    在这里插入图片描述
    对这个文档类型声明而言,publicId 是"-//W3C//DTD HTML 4.01//EN",而 systemId 是"http: //www.w3.org/TR/html4/strict.dtd"
  • 在支持 DOM2 级的浏览器中,应该可以运行下列代码。
 alert(document.doctype.publicId);
alert(document.doctype.systemId);

实际上,很少需要在网页中访问此类信息。

  1. 最后一个属性 internalSubset,用于访问包含在文档类型声明中的额外定义,以下面的代码为例。
    在这里插入图片描述
    访问 document.doctype.internalSubset 将得到"<!ELEMENT name (#PCDATA)>"。这种内部子集(internal subset)在 HTML 中极少用到,在 XML 中可能会更常见一些
2、Document 类型的变化
  1. importNode()方法:Document 类型的变化中唯一与命名空间无关的方法是 importNode()。
  • 这个方法的用途:从一个文档中取得一个节点,然后将其导入到另一个文档,使其成为这个文档结构的一部分。【需要注意的是, 每个节点都有一个 ownerDocument 属性,表示所属的文档。】
  • 如果调用 appendChild()时传入的节点属于不同的文档(ownerDocument 属性的值不一样),则会导致错误但在调用 importNode()时传入不同文档的节点则会返回一个新节点这个新节点的所有权归当前文档所有
  • importNode()方法与 Element 的 cloneNode()方法非常相似,它接受两个参数要复制的节点和一个表示是否复制子节点的布尔值。返回的结果是原来节点的副本,但能够在当前文档中使用。来看下面的例子:
var newNode = document.importNode(oldNode, true); //导入节点及其所有子节点 
document.body.appendChild(newNode);

这个方法在 HTML 文档中并不常用,在 XML 文档中用得比较多(更多讨论请参见第 18 章)。

  1. defaultView 的属性:“DOM2 级视图”模块添加了一个名为 defaultView 的属性,其中保存着一个指针,指向拥有给定文档的窗口(或框架)。除 IE 之外的所有浏览器都支持 defaultView 属性。在 IE 中有一个等价的属性名叫 parentWindow(Opera 也支持这个属性)。因此,要确定文档的归属窗口,可以使用以下代码。
var parentWindow = document.defaultView || document.parentWindow;
  1. createDocumentType()createDocument():“DOM2 级核心”还为 document.implementation 对象规定了两个新方法:createDocumentType()和 createDocument()。
  • createDocumentType():用于创建一个新的 DocumentType 节点,接受 3 个参数:文档类型名称publicIdsystemId。例如,下列代码会创建一个新的 HTML 4.01 Strict 文档类型。
    在这里插入图片描述

由于既有文档的文档类型不能改变,因此 createDocumentType()只在创建新文档时有用;

  • createDocument():创建新文档时需要用到 createDocument()方法。这个方法接受 3 个参数:针对文档中元素的 namespaceURI文档元素的标签名新文档的文档类型。下面这行代码将会创建一个空的新 XML 文档
var doc = document.implementation.createDocument("", "root", null);

这行代码会创建一个没有命名空间的新文档,文档元素为<root>,而且没有指定文档类型。要想创建一个 XHTML 文档,可以使用以下代码
在这里插入图片描述
这样,就创建了一个带有适当命名空间和文档类型的新 XHTML 文档。不过,新文档当前只有文档元素<html>,剩下的所有元素都需要继续添加。

  1. createHTMLDocument(): “DOM2 级 HTML”模块也为 document.implementation 新增了一个方法,名叫createHTMLDocument()。
  • 这个方法的用途创建一个完整的 HTML 文档,包括<html><head><title><body>元素。这个方法只接受一个参数,即新创建文档的标题(放在元素中的字符串)返回新的 HTML 文档,如下所示:
var htmldoc = document.implementation.createHTMLDocument("New Doc"); alert(htmldoc.title); //"New Doc"
alert(typeof htmldoc.body); //"object"

通过调用 createHTMLDocument()创建的这个文档,是 HTMLDocument 类型的实例,因而具有该类型的所有属性和方法,包括 title 和 body 属性。只有 Opera 和 Safari 支持这个方法。

3、Node类型的变化
  1. isSupported()方法Node 类型中唯一与命名空间无关的变化,就是添加了 isSupported()方法。 DOM1 级为 document.implementation引入的hasFeature()方法类似
  • isSupported()方法作用:确定当前节点具有什么能力。这个方法也接受相同的两个参数:特性名和特性版本号。如果浏览器实现了相应特性,而且能够基于给定节点执行该特性,isSupported()就返回 true。来看一个例子:
if (document.body.isSupported("HTML", "2.0")){ 
	//执行只有"DOM2 级 HTML"才支持的操作
}

由于不同实现在决定对什么特性返回 true 或 false 时并不一致,这个方法同样也存在与 hasFeature() 方法相同的问题。为此,我们建议在确定某个特性是否可用时,最好还是使用能力检测

  1. isSameNode()isEqualNode()DOM3 级引入的两个辅助比较节点的方法。这两个方法都接受一个节点参数,并在传入节点与引用的节点相同或相等时返回 true
  • 所谓相同,指的是两个节点引用的是同一个对象
    所谓相等,指的是两个节点是相同的类型具有相等的属性(nodeName、nodeValue, 等等),而且它们的 attributes 和 childNodes 属性也相等(相同位置包含相同的值)。来看一个例子
var div1 = document.createElement("div"); 
 div1.setAttribute("class", "box");
var div2 = document.createElement("div");
div2.setAttribute("class", "box");
alert(div1.isSameNode(div1)); //true 
alert(div1.isEqualNode(div2)); //true 
alert(div1.isSameNode(div2)); //false

这里创建了两个具有相同特性的<div>元素。这两个元素相等,但不相同

  1. setUserData()方法和getUserData()方法(可能已经弃用):DOM3 级还针对为 DOM 节点添加额外数据引入了新方法。其中,setUserData()方法会将数据指定给节点,它接受 3 个参数:要设置的键实际的数据(可以是任何数据类型)和处理函数。以下代码可以将数据指定给一个节点。(要设置的键指的是什么?是属性吗?)
document.body.setUserData("name", "Nicholas", function(){});
  • 然后,使用 getUserData()并传入相同的键,就可以取得该数据,如下所示: 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);
alert(newDiv.getUserData("name"));      //"Nicholas"

这里,先创建了一个<div>元素,然后又为它添加了一些数据(用户数据)。在使用 cloneNode() 复制这个元素时,就会调用处理函数,从而将数据自动复制到了副本节点。结果在通过副本节点调用 getUserData()时,就会返回与原始节点中包含的相同的值。

4、 框架的变化
  1. contentDocument属性框架和内嵌框架分别用 HTMLFrameElement 和 HTMLIFrameElement 表示,它们在 DOM2 级中都有了一个新属性,名叫 contentDocument。
  • 这个属性包含一个指针,指向表示框架内容的文档对象(返回的是个对象)。在此之前,无法直接通过元素取得这个文档对象(只能使用 frames 集合)。可以像下面这样使用这个属性:
var iframe = document.getElementById("myIframe");
var iframeDoc = iframe.contentDocument; //在 IE8 以前的版本中无效

由于 contentDocument 属性是 Document 类型的实例,因此可以像使用其他 HTML 文档一样使用它,包括所有属性和方法。Opera、Firefox、Safari 和 Chrome 支持这个属性。

  • IE8 之前不支持框架中的 contentDocument 属性,但支持一个名叫 contentWindow 的属性,该属性返回框架的 window 对象,而这个 window 对象又有一个 document 属性。因此,要想在上述所有浏览器中访问内嵌框架的文档对象,可以使用下列代码。
var iframe = document.getElementById("myIframe");
var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;

所有浏览器都支持 contentWindow 属性。

访问框架或内嵌框架的文档对象要受到跨域安全策略的限制。如果某个框架中的页面来自其他域或不同子域,或者使用了不同的协议,那么要访问这个框架的文档对象就会导致错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>