JavaScript高级程序设计之DOM2和DOM3之DOM 变化之其他方面的变化第12.1.2讲

DOM 的其他部分在“DOM2 级核心”中也发生了一些变化。这些变化与XML 命名空间无关,而是
更倾向于确保API 的可靠性及完整性。
1. DocumentType 类型的变化
DocumentType 类型新增了3 个属性:publicId、systemId 和internalSubset。其中,前两
个属性表示的是文档类型声明中的两个信息段,这两个信息段在DOM1 级中是没有办法访问到的。以
下面的HTML 文档类型声明为例。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">

对这个文档类型声明而言,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);
实际上,很少需要在网页中访问此类信息。
最后一个属性internalSubset,用于访问包含在文档类型声明中的额外定义,以下面的代码为例。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
[<!ELEMENT name (#PCDATA)>] >
访问document.doctype.internalSubset 将得到"<!ELEMENT name (#PCDATA)>"。这种内部
子集(internal subset)在HTML 中极少用到,在XML 中可能会更常见一些。
2. Document 类型的变化
Document 类型的变化中唯一与命名空间无关的方法是importNode()。这个方法的用途是从一个
文档中取得一个节点,然后将其导入到另一个文档,使其成为这个文档结构的一部分。需要注意的是,
每个节点都有一个ownerDocument 属性,表示所属的文档。如果调用appendChild()时传入的节点
属于不同的文档(ownerDocument 属性的值不一样),则会导致错误。但在调用importNode()时传入
不同文档的节点则会返回一个新节点,这个新节点的所有权归当前文档所有。
说起来,importNode()方法与Element 的cloneNode()方法非常相似,它接受两个参数:要复

制的节点和一个表示是否复制子节点的布尔值。返回的结果是原来节点的副本,但能够在当前文档中使
用。来看下面的例子:

var newNode = document.importNode(oldNode, true); //导入节点及其所有子节点
document.body.appendChild(newNode);
这个方法在HTML 文档中并不常用,在XML 文档中用得比较多(更多讨论请参见第18 章)。
“DOM2 级视图”模块添加了一个名为defaultView 的属性,其中保存着一个指针,指向拥有给
定文档的窗口(或框架)。除此之外,“视图”规范没有提供什么时候其他视图可用的信息,因而这是唯
一一个新增的属性。除IE 之外的所有浏览器都支持defaultView 属性。在IE 中有一个等价的属性名
叫parentWindow(Opera 也支持这个属性)。因此,要确定文档的归属窗口,可以使用以下代码。

var parentWindow = document.defaultView || document.parentWindow;
var parentWindow = document.defaultView || document.parentWindow;
除了上述一个方法和一个属性之外,“DOM2 级核心”还为document.implementation 对象规定了
两个新方法:createDocumentType()和createDocument()。前者用于创建一个新的DocumentType
节点,接受3 个参数:文档类型名称、publicId、systemId。例如,下列代码会创建一个新的HTML
4.01 Strict 文档类型

var doctype = document.implementation.createDocumentType("html",
"-//W3C//DTD HTML 4.01//EN",
"http://www.w3.org/TR/html4/strict.dtd");
由于既有文档的文档类型不能改变,因此createDocumentType()只在创建新文档时有用;创建
新文档时需要用到createDocument()方法。这个方法接受3 个参数:针对文档中元素的namesp-
aceURI、文档元素的标签名、新文档的文档类型。下面这行代码将会创建一个空的新XML 文档。

var doc = document.implementation.createDocument("", "root", null);
这行代码会创建一个没有命名空间的新文档,文档元素为<root>,而且没有指定文档类型。要想
创建一个XHTML 文档,可以使用以下代码。

var doctype = document.implementation.createDocumentType("html",
" -//W3C//DTD XHTML 1.0 Strict//EN",
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd");
var doc = document.implementation.createDocument("http://www.w3.org/1999/xhtml",
"html", doctype);
这样,就创建了一个带有适当命名空间和文档类型的新XHTML 文档。不过,新文档当前只有文档
元素<html>,剩下的所有元素都需要继续添加。
“DOM2 级HTML”模块也为document.implementation 新增了一个方法,名叫createHTML-
Document()。这个方法的用途是创建一个完整的HTML 文档,包括<html>、<head>、<title>和
<body>元素。这个方法只接受一个参数,即新创建文档的标题(放在<title>元素中的字符串),返回
新的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 类型的变化
Node 类型中唯一与命名空间无关的变化,就是添加了isSupported()方法。与DOM1 级为docum-
ent.implementation 引入的hasFeature()方法类似,isSupported()方法用于确定当前节点具有
什么能力。这个方法也接受相同的两个参数:特性名和特性版本号。如果浏览器实现了相应特性,而且
能够基于给定节点执行该特性,isSupported()就返回true。来看一个例子:

if (document.body.isSupported("HTML", "2.0")){
//执行只有"DOM2 级HTML"才支持的操作
}
由于不同实现在决定对什么特性返回true 或false 时并不一致,这个方法同样也存在与hasFeature()
方法相同的问题。为此,我们建议在确定某个特性是否可用时,最好还是使用能力检测。
DOM3 级引入了两个辅助比较节点的方法:isSameNode()和isEqualNode()。这两个方法都接受
一个节点参数,并在传入节点与引用的节点相同或相等时返回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>元素。这两个元素相等,但不相同。
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.框架的变化
框架和内嵌框架分别用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 属性。
访问框架或内嵌框架的文档对象要受到跨域安全策略的限制。如果某个框架中的
页面来自其他域或不同子域,或者使用了不同的协议,那么要访问这个框架的文档对
象就会导致错误。











你可能感兴趣的:(JavaScript,js,开发,JS基础知识)