第十四章 DOM

您所在的位置:网站首页 html内嵌网页指定 第十四章 DOM

第十四章 DOM

2023-03-21 13:36| 来源: 网络整理| 查看: 265

14.1.1 Node类型2.节点关系14.1.2 Document类型1.文档子节点2.文档信息3.定位元素4.特殊集合5.DOM兼容性检测6.文档写入14.1.3 Element类型1.HTML元素2.取得属性3.设置属性5.创建元素6.元素后代14.1.4 Text类型1.创建文本节点2.规范化文本节点3.拆分文本节点14.1.5 Comment类型14.1.6 CDATASection类型14.1.7 DocumentType类型14.1.8 DocumentFragment类型14.1.9 Attr类型

任何HTML或XML文档都可以用DOM表示为一个由节点构成的层级结构。节点分很多类型,每种类型对应着文档中不同的信息和(或)标记,也都有自己不同的特性、数据和方法,而且与其他类型有某种关系。这些关系构成了层级,让标记可以表示为一个以特定节点为根的树形结构。以下面的HTML为例:

Sample Page Hello World!

表示为层级结构:document节点表示每个文档的根节点。在这里,根节点的唯一子节点是元素,我们称之为文档元素(documentElement)。文档元素是文档最外层的元素,所有其他元素都存在于这个元素之内。每个文档只能有一个文档元素。在HTML页面中,文档元素始终是元素。在XML文档中,则没有这样预定义的元素,任何元素都可能成为文档元素。HTML中的每段标记都可以表示为这个树形结构中的一个节点。元素节点表示HTML元素,属性节点表示属性,文档类型节点表示文档类型,注释节点表示注释。DOM中总共有12种节点类型,这些类型都继承一种基本类型。

14.1.1 Node类型

DOM Level 1描述了名为Node的接口,所有DOM节点类型都必须实现这个接口。Node接口在JavaScript中被实现为Node类型,在除IE之外的所有浏览器中,都可以直接访问这个类型。在JavaScript中,所有节点类型都继承Node类型,因此所有类型都共享相同的基本属性和方法。每个节点都有nodeType属性,表示该节点的类型。节点类型由定义在Node类型上的12个数值常量表示:❑ Node.ELEMENT_NODE(1) ❑ Node.ATTRIBUTE_NODE(2) ❑ Node.TEXT_NODE(3) ❑ Node.CDATA_SECTION_NODE(4)❑ Node.ENTITY_REFERENCE_NODE(5) ❑ Node.ENTITY_NODE(6)❑ Node.PROCESSING_INSTRUCTION_NODE(7) ❑ Node.COMMENT_NODE(8)❑ Node.DOCUMENT_NODE(9) ❑ Node.DOCUMENT_TYPE_NODE(10)❑ Node.DOCUMENT_FRAGMENT_NODE(11) ❑ Node.NOTATION_NODE(12)节点类型可通过与这些常量比较来确定

if (someNode.nodeType == Node.ELEMENT_NODE) { console.log('Node is an element.');}

先检查了节点是不是元素。如果是,则将其nodeName的值赋给一个变量。对元素而言,nodeName始终等于元素的标签名,而nodeValue则始终为null。

2.节点关系

文档中的所有节点都与其他节点有关系。这些关系可以形容为家族关系,相当于把文档树比作家谱。在HTML中,元素是元素的子元素,而元素则是元素的父元素。元素是元素的同胞元素,因为它们有共同的父元素。每个节点都有一个childNodes属性,其中包含一个NodeList的实例。NodeList是一个类数组对象,用于存储可以按位置存取的有序节点。注:NodeList并不是Array的实例,但可以使用中括号访问它的值,而且它也有length属性。NodeList对象独特的地方在于,它其实是一个对DOM结构的查询,因此DOM结构的变化会自动地在NodeList中反映出来。我们通常说NodeList是实时的活动对象,而不是第一次访问时所获得内容的快照。例子展示了:如何使用中括号或使用item()方法访问NodeList中的元素:

let firstChild = someNode.childNodes[0];let secondChild = someNode.childNodes.item(1);let count = someNode.childNodes.length;

使用中括号或者item()方法都可以,但多数开发者倾向于使用中括号,因为它是一个类数组对象。注:length属性表示那一时刻NodeList中节点的数量。使用Array.prototype. slice()可以像前面介绍arguments时一样把NodeList对象转换为数组。

let arrayOfNodes = Array.prototype.slice.call(someNode.childNodes, 0);

使用ES6的Array.from()静态方法,可以替换这种笨拙的方式:

let arrayOfNodes = Array.from(someNode.childNodes);

每个节点都有一个parentNode属性,指向其DOM树中的父元素。childNodes中的所有节点都有同一个父元素,因此它们的parentNode属性都指向同一个节点。此外,childNodes列表中的每个节点都是同一列表中其他节点的同胞节点。使用previousSibling和nextSibling可以在这个列表的节点间导航。这个列表中第一个节点的previousSibling属性是null,最后一个节点的nextSibling属性也是null,如下所示:

if (someNode.nextSibling === null) { console.log('父节点的最后一个子节点');} else if(someNode.previousSibling === null) { console.log('父节点的第一个子节点');}

如果childNodes中只有一个节点,则它的previousSibling和nextSibling属性都是null。父节点和它的第一个及最后一个子节点也有专门属性:firstChild和lastChild分别指向childNodes中的第一个和最后一个子节点。someNode.firstChild的值始终等于someNode. childNodes[0],someNode.lastChild的值始终等于someNode.childNodes[someNode. childNodes.length-1]。如果只有一个子节点,则firstChild和lastChild指向同一个节点。如果没有子节点,则firstChild和lastChild都是null。上述这些节点之间的关系为在文档树的节点之间导航提供了方便。有了这些关系,childNodes属性的作用远不止是必备属性那么简单了,原因:利用这些关系指针,几乎可以访问到文档树中的任何节点,而这种便利性是childNodes的最大亮点。方法:hasChildNodes(),若返回true则说明节点有一个或多个子节点。相比查询childNodes的length属性,这个方法更方便。最后还有一个所有节点都共享的关系。ownerDocument属性,是一个指向代表整个文档的文档节点的指针。所有节点都被创建它们(或自己所在)的文档所拥有,因为一个节点不可能同时存在于两个或者多个文档中。这个属性为迅速访问文档节点提供了便利,因为无需在文档结构中逐层上溯了。注意 虽然所有节点类型都继承了Node,但并非所有节点都有子节点。3.操纵节点因为所有关系指针都是只读的,所以DOM又提供了一些操纵节点的方法。最常用的:appendChild(),用于在childNodes列表末尾添加节点。添加新节点会更新相关的关系指针,包括父节点和之前的最后一个子节点。appendChild()方法返回新添加的节点

let returnedNode = someNode.appendChild(newNode);console.log(returnedNode == newNode); // appendChild()方法返回新添加的节点console.log(someNode.lastNode == newNode); // 添加新节点会更新相关的关系指针,包括父节点和之前的最后一个子节点

如果把文档中已经存在的节点传给appendChild(),则这个节点会从之前的位置被转移到新位置。即使DOM树通过各种关系指针维系,一个节点也不会在文档中同时出现在两个或更多个地方。insertBefore()方法,把节点放到childNodes中的特定位置而不是末尾或开头。接收两个参数:要插入的节点和参照节点。调用这个方法后,要插入的节点会变成参照节点的前一个同胞节点,并被返回。如果参照节点是null,则insertBefore()与appendChild()效果相同

// 作为最后一个子节点插入returnedNode = someNode.insertBefore(newNode, null);console.log(newNode == someNode.lastNode); //如果参照节点是null,则insertBefore()与appendChild()效果相同// 作为新的第一个子节点插入returnedNode = someNode.insertBefore(newNode, someNode.firstChild);console.log(newNode == someNode.firstChild); // 要插入的节点会变成参照节点的前一个同胞节点// 插入最后一个子节点前面returnedNode = someNode.insertBefore(newNode, someNode.lastNode);console.log(newNode == someNode.childNodes[someNode.childNodes.length - 2]); //

appendChild()和insertBefore()在插入节点时不会删除任何已有节点。replaceChild()方法接收两个参数:要插入的节点和要替换的节点。要替换的节点会被返回并从文档树中完全移除,要插入的节点会取而代之。所有关系指针都会从被替换的节点复制过来。要移除节点,使用removeChild()方法。这个方法接收一个参数,即要移除的节点。被移除的节点会被返回上面介绍的4个方法都用于操纵某个节点的子元素,也就是说使用它们之前必须先取得父节点(使用前面介绍的parentNode属性)。并非所有节点类型都有子节点,如果在不支持子节点的节点上调用这些方法,则会导致抛出错误。4.其他方法所有节点类型还共享了两个方法。第一个是cloneNode(),返回与调用它的节点一模一样的节点。cloneNode()方法接收一个布尔值参数,表示是否深复制。传入true参数时,会进行深复制,即复制节点及其整个子DOM树。传入false,则只会复制调用该方法的节点。复制返回的节点属于文档所有,但尚未指定父节点,所以可称为孤儿节点(orphan)。可以通过appendChild()、insertBefore()或replaceChild()方法把孤儿节点添加到文档中。

item1 item2 item3

若myList保存着对这个

元素的引用,则下列代码展示了使用cloneNode()方法的两种方式:

let deepList = myList.cloneNode(true);console.log(deepList.childNodes.length); // 3(IE9之前的版本)或7(其他浏览器let shallowList = myList.cloneNode(false);console.log(shallowList.childNodes.length);// 0

deepList保存着myList的副本。deepList有3个列表项,每个列表项又各自包含文本。变量shallowList则保存着myList的浅副本,因此没有子节点。注: cloneNode()方法不会复制添加到DOM节点的JavaScript属性,比如事件处理程序。这个方法只复制HTML属性,以及可选地复制子节点。除此之外则一概不会复制。IE在很长时间内会复制事件处理程序,这是一个bug,所以推荐在复制前先删除事件处理程序。normalize(),这个方法唯一的任务是处理文档子树中的文本节点。由于解析器实现的差异或DOM操作等原因,可能会出现并不包含文本的文本节点,或者文本节点之间互为同胞关系。在节点上调用normalize()方法会检测这个节点的所有后代,从中搜索上述两种情形。如果发现空文本节点,则将其删除;如果两个同胞节点是相邻的,则将其合并为一个文本节点。

14.1.2 Document类型

Document类型是JavaScript中表示文档节点的类型。在浏览器中,文档对象document是HTMLDocument的实例(HTMLDocument继承Document),表示整个HTML页面。document是window对象的属性,因此是一个全局对象。Document类型的节点有以下特征:❑ nodeType等于9; ❑ nodeName值为”#document”;❑ nodeValue值为null; ❑ parentNode值为null;❑ ownerDocument值为null; ❑ 子节点可以是DocumentType(最多一个)、Element(最多一个)、ProcessingInstruction或Comment类型。Document类型可以表示HTML页面或其他XML文档,但最常用的还是通过HTMLDocument的实例取得document对象。document对象可用于获取关于页面的信息以及操纵其外观和底层结构。

1.文档子节点

虽然DOM规范规定Document节点的子节点可以是DocumentType、Element、Processing-Instruction或Comment,但也提供了两个访问子节点的快捷方式:第一个是documentElement属性,始终指向HTML页面中的元素。虽然document.childNodes中始终有元素,但使用documentElement属性可以更快更直接地访问该元素。

浏览器解析完这个页面之后,文档只有一个子节点,即元素。这个元素既可以通过documentElement属性获取,也可以通过childNodes列表访问:

let html = document.documentElement; // 取得对的引用console.log(html === document.childNodes[0]); // trueconsole.log(html === document.firstChild); // true

作为HTMLDocument的实例,document对象还有一个body属性,直接指向元素。因为这个元素是开发者使用最多的元素,所以JavaScript代码中经常可以看到document.body

let body = document.body; // 取得对的引用// 所有主流浏览器都支持document.documentElement和document.body

Document类型另一种可能的子节点是DocumentType。标签是文档中独立的部分,其信息可以通过doctype属性(在浏览器中是document.doctype)来访问

let doctype = document.doctype; // 取得对的引用

另外,严格来讲出现在元素外面的注释也是文档的子节点,它们的类型是Comment。不过,由于浏览器实现不同,这些注释不一定能被识别,或者表现可能不一致一般来说,appendChild()、removeChild()和replaceChild()方法不会用在document对象上。因为文档类型(如果存在)是只读的,而且只能有一个Element类型的子节点(即,已经存在了)。

2.文档信息

document作为HTMLDocument的实例,还有一些标准Document对象上所没有的属性。这些属性提供浏览器所加载网页的信息。第一个属性是title,包含

元素中的文本,通常显示在浏览器窗口或标签页的标题栏。通过这个属性可以读写页面的标题,修改后的标题也会反映在浏览器标题栏上。不过,修改title属性并不会改变元素

let originalTitle = document.title; // 读取文档标题 console.log(originalTitle); document.title = 'New Title'; // 修改文档标题 console.log(document.title);

介绍3个属性:URL、domain和referrer。URL包含当前页面的完整URL(地址栏中的URL)domain包含页面的域名referrer包含链接到当前页面的那个页面的URL。如果当前页面没有来源,则referrer属性包含空字符串。所有这些信息都可以在请求的HTTP头部信息中获取,只是在JavaScript中通过这几个属性暴露出来而已

let url = document.URL; // 取得完整的URL let domain = document.domain; // 取得域名 let referrer = document.referrer; // 取得来源

URL跟域名是相关的。比如,如果document.URL是http://www.wrox.com/WileyCDA/,则document.domain就是www.wrox.com。在这些属性中,只有domain属性可设置。出于安全考虑,给domain属性设置的值是有限制的。如果URL包含子域名如p2p.wrox.com,则可以将domain设置为”wrox.com”(URL包含“www”时也一样,比如www.wrox.com)。不能给domain属性设置URL中不包含的值

// 页面来自p2p.wrox.com document.domain = 'wrox.com'; // 成功 document.domain = 'nczonline.com'; // 出错!

当页面中包含来自某个不同子域的窗格()或内嵌窗格()时,设置document.domain是有用的。因为跨源通信存在安全隐患,所以不同子域的页面间无法通过JavaScript通信。此时,在每个页面上把document.domain设置为相同的值,这些页面就可以访问对方的JavaScript对象了。比如,一个加载自www.wrox.com的页面中包含一个内嵌窗格,其中的页面加载自p2p.wrox.com。这两个页面的document.domain包含不同的字符串,内部和外部页面相互之间不能访问对方的JavaScript对象。如果每个页面都把document.domain设置为wrox.com,那这两个页面之间就可以通信了。浏览器对domain属性有一个限制,即domain属性一旦放松就不能再收紧。比如,把document.domain设置为”wrox.com”之后,就不能再将其设置回”p2p.wrox.com”,后者会导致错误

3.定位元素

使用DOM最常见的情形:获取某个或某组元素的引用,然后对它们执行某些操作。document对象上暴露了一些方法,可以实现这些操作。getElementById()和getElementsByTagName()是Document类型提供的两个方法。● getElementById()方法接收一个参数,即要获取元素的ID。如果找到了则返回这个元素,如果没找到则返回null。参数ID必须跟元素在页面中的id属性值完全匹配,包括大小写。如果页面中存在多个具有相同ID的元素,则getElementById()返回在文档中出现的第一个元素。● getElementsByTagName()用来获取元素引用。接收一个参数,即要获取元素的标签名返回包含零个或多个元素的NodeList。在HTML文档中,这个方法返回一个HTMLCollection对象。考虑到二者都是“实时”列表,HTMLCollection与NodeList是很相似的。例如,下面的代码会取得页面中所有的元素并返回包含它们的HTMLCollection,返回的HTMLCollection对象保存在了变量images中。与NodeList对象一样,也可以使用中括号或item()方法从HTMLCollection取得特定的元素。而取得元素的数量同样可以通过length属性得知

let images = document.getElementsByTagName('img'); console.log(images.length); // 图片数量 console.log(images[0].src); // 第一张图片的src属性 console.log(images.item(0).src); // 同上

HTMLCollection对象还有一个额外的方法namedItem(),可通过标签的name属性取得某一项的引用。例如,假设页面中包含如下的元素,可以用namedItem()从images中取得对这个元素的引用,对于name属性的元素,还可以直接使用中括号来获取

let images = document.getElementsByTagName('img'); let myImage = images.nameItem('myImage'); // 用namedItem()从images中取得对这个元素的引用 let myImage = images['myInage']; // name属性的元素,还可直接使用中括号来获取

对HTMLCollection对象而言,中括号既可以接收数值索引,也可以接收字符串索引。而在后台,数值索引会调用item(),字符串索引会调用namedItem()。要取得文档中的所有元素,可以给getElementsByTagName()传入*。在JavaScript和CSS中,*一般被认为是匹配一切的字符。● 获取元素的第三个方法是getElementsByName()返回具有给定name属性的所有元素最常用于单选按钮,因为同一字段的单选按钮必须具有相同的name属性才能确保把正确的值发送给服务器

Red Green Blue let radios = document.getElementsByName('color');

所有单选按钮都有名为”color”的name属性,但它们的ID都不一样。这是因为ID是为了匹配对应的元素,而name相同是为了保证只将三个中的一个值发送给服务器。然后就可以getElementsByName()取得所有单选按钮与getElementsByTagName()一样,getElementsByName()方法也返回HTMLCollection。不过在这种情况下,namedItem()方法只会取得第一项(因为所有项的name属性都一样)

4.特殊集合

document对象上还暴露了几个特殊集合,也都是HTMLCollection的实例。是访问文档中公共部分的快捷方式,列举如下:❑ document.anchors包含文档中所有带name属性的元素。❑ document.applets包含文档中所有元素(因为元素已经不建议使用,所以这个集合已经废弃)。❑ document.forms包含文档中所有元素(与document.getElementsByTagName (“form”)返回的结果相同)。❑ document.images包含文档中所有元素(与document.getElementsByTagName (“img”)返回的结果相同)。❑ document.links包含文档中所有带href属性的元素。这些特殊集合始终存在于HTMLDocument对象上,而且与所有HTMLCollection对象一样,其内容也会实时更新以符合当前文档的内容。

5.DOM兼容性检测

由于DOM有多个Level和多个部分,因此确定浏览器实现了DOM的哪些部分是很必要的。document.implementation属性是一个对象,其中提供了与浏览器DOM实现相关的信息和能力。DOM Level 1在document.implementation上只定义了一个方法,即hasFeature()接收两个参数:特性名称和DOM版本。如果浏览器支持指定的特性和版本,则hasFeature()方法返回true

let hasXmlDom = document.implementation.hasFeature('XML', '1.0');

由于实现不一致,因此hasFeature()的返回值并不可靠。目前这个方法已经被废弃,不再建议使用。为了向后兼容,目前主流浏览器仍然支持这个方法,但无论检测什么都一律返回true。

6.文档写入

document对象可以向网页输出流中写入内容。对应4个方法:write()、writeln()、open()和close()write()和writeln()方法都接收一个字符串参数,可以将这个字符串写入网页中。write()简单地写入文本,而writeln()还会在字符串末尾追加一个换行符(\n)。这两个方法可以用来在页面加载期间向页面中动态添加内容write()和writeln()方法经常用于动态包含外部资源,如JavaScript文件。

document.write("" + ""); // 错误 document.write("" + ""); // 正确

在包含JavaScript文件时,不能像如下这样直接包含字符串”“,因为这个字符串会被解释为脚本块的结尾,导致后面的代码不能执行;字符串””不会再匹配最外层的标签,因此不会在页面中输出额外内容。如果在页面加载完后再调用document.write(),则输出的内容会重写整个页面使用了window.onload事件处理程序open()和close()方法分别用于打开和关闭网页输出流。在调用write()和writeln()时,这两个方法都不是必需的。

14.1.3 Element类型

除了Document类型,Element类型是Web开发中最常用的类型。Element表示XML或HTML元素,对外暴露出访问元素标签名、子节点和属性的能力。Element类型的节点具有以下特征:❑ nodeType等于1; ❑ nodeName值为元素的标签名;❑ nodeValue值为null; ❑ parentNode值为Document或Element对象;❑ 子节点可以是Element、Text、Comment、ProcessingInstruction、CDATASection、EntityReference类型。可以通过nodeName或tagName属性来获取元素的标签名。这两个属性返回同样的值(添加后一个属性明显是为了不让人误会)。

let div = document.getElementById('myDiv'); // 取得这个元素的标签名 console.log(div.tagName); // DIV console.log(div.tagName == div.nodeName); // true

注:div.tagName实际上返回的是”DIV”而不是”div”。在HTML中,元素标签名始终以全大写表示;在XML(包括XHTML)中,标签名始终与源代码中的大小写一致。如果不确定脚本是在HTML文档还是XML文档中运行,最好将标签名转换为小写形式

1.HTML元素

所有HTML元素都通过HTMLElement类型表示,包括其直接实例和间接实例。另外,HTMLElement直接继承Element并增加了一些属性。每个属性都对应下列属性之一,它们是所有HTML元素上都有的标准属性:❑ id,元素在文档中的唯一标识符; ❑ title,包含元素的额外信息,通常以提示条形式展示;❑ lang,元素内容的语言代码(很少用); ❑ dir,语言的书写方向(”ltr”表示从左到右,”rtl”表示从右到左,同样很少用);❑ className,相当于class属性,用于指定元素的CSS类(因为class是ECMAScript关键字,所以不能直接用这个名字)。所有这些都可以用来获取对应的属性值,也可以用来修改相应的值并非所有这些属性的修改都会对页面产生影响。比如,把id或lang改成其他值对用户是不可见的(假设没有基于这两个属性应用CSS样式),而修改title属性则只会在鼠标移到这个元素上时才会反映出来。修改dir会导致页面文本立即向左或向右对齐。修改className会立即反映应用到新类名的CSS样式(如果定义了不同的样式)。

2.取得属性

与属性相关的DOM方法主要有3个:getAttribute()、setAttribute()和removeAttribute()。这些方法主要用于操纵属性,包括在HTMLElement类型上定义的属性。注:传给getAttribute()的属性名与它们实际的属性名是一样的,要传”class”而非”className”(className是作为对象属性时才那么拼写的)。如果给定的属性不存在,则getAttribute()返回nullgetAttribute()方法也能取得不是HTML语言正式属性的自定义属性的值。注:属性名不区分大小写,因此”ID”和”id”被认为是同一个属性。根据HTML5规范的要求,自定义属性名应该前缀data-以方便验证。元素的所有属性也可以通过相应DOM元素对象的属性来取得。包括HTMLElement上定义的直接映射对应属性的5个属性,还有所有公认(非自定义)的属性也会被添加为DOM对象的属性。开发者在进行DOM编程时,通常会放弃使用getAttribute(),而只使用对象属性。getAttribute()主要用于取得自定义属性的值。

3.设置属性

与getAttribute()配套的方法是setAttribute()接收两个参数:要设置的属性名和属性的值。如果属性已经存在,则setAttribute()会以指定的值替换原来的值;如果属性不存在,则setAttribute()会以指定的值创建该属性。适用于HTML属性,也适用于自定义属性。另外,使用setAttribute()方法设置的属性名会规范为小写形式,因此”ID”会变成”id”。因为元素属性也是DOM对象属性,所以直接给DOM对象的属性赋值也可以设置元素属性的值注:在DOM对象上添加自定义属性,不会自动让它变成元素的属性。在多数浏览器中,这个属性不会自动变成元素属性

div.mycolor = 'red'; console.log(div.getAttribute('myColor')); // null

removeAttribute()用于从元素中删除属性。不单单是清除属性的值,而是会把整个属性完全从元素中去掉用得并不多,但在序列化DOM元素时可以通过它控制要包含的属性。4.attributes属性Element类型是唯一使用attributes属性的DOM节点类型。attributes属性包含一个NamedNodeMap实例,是一个类似NodeList的“实时”集合。元素的每个属性都表示为一个Attr节点,并保存在这个NamedNodeMap对象中。NamedNodeMap对象包含下列方法:❑ getNamedItem(name),返回nodeName属性等于name的节点;❑ removeNamedItem(name),删除nodeName属性等于name的节点;❑ setNamedItem(node),向列表中添加node节点,以其nodeName为索引;❑ item(pos),返回索引位置pos处的节点。attributes属性中的每个节点的nodeName是对应属性的名字,nodeValue是属性的值。比如,要取得元素id属性的值,可以使用以下代码:

let id = element.attributes.getNamedItem('id').nodeValue; // 使用中括号访问属性的简写形式 let id = element.attributes['id'].nodeValue;

也可以用这种语法设置属性的值,即先取得属性节点,再将其nodeValue设置为新值

element.attributes['id'].nodeValue = 'someotherId';

removeNamedItem()方法与元素上的removeAttribute()方法类似,也是删除指定名字的属性。唯一的不同之处:removeNamedItem()返回表示被删除属性的Attr节点setNamedItem()方法很少使用,它接收一个属性节点,然后给元素添加一个新属性一般来说,因为使用起来更简便,通常开发者更喜欢使用getAttribute()、removeAttribute()和setAttribute()方法,而不是刚刚介绍的NamedNodeMap对象的方法。attributes属性最有用的场景:需要迭代元素上所有属性时。要把DOM结构序列化为XML或HTML字符串。比如,以下代码能够迭代一个元素上的所有属性并以attribute1=”value1” attribute2=”value2”的形式,生成格式化字符串:

function outputAttributes(element) { let pairs = []; for(let i = 0, len = element.attributs.length; i < len; ++i) { const attribute = element.attributes[i]; pairs.push(`${attribute.nodeName} = ${attribute.nodeValue}`); } return pairs.join(' '); }

这个函数使用数组存储每个名/值对,迭代完所有属性后,再将这些名/值对用空格拼接在一起。(这个技术常用于序列化为长字符串。)函数中的for循环使用attributes.length属性迭代每个属性,将每个属性的名字和值输出为字符串。不同浏览器返回的attributes中的属性顺序也可能不一样。HTML或XML代码中属性出现的顺序不一定与attributes中的顺序一致。

5.创建元素

document.createElement()方法创建新元素。接收一个参数,即要创建元素的标签名。在HTML文档中,标签名不区分大小写,而XML文档(包括XHTML)区分大小写。要创建元素,可以使用下面的代码:

let div = document.createElement('div');

在新元素上设置属性只会附加信息。因为这个元素还没有添加到文档树,所以不会影响浏览器显示。要把元素添加到文档树,可以使用appendChild()、insertBefore()或replaceChild()。元素被添加到文档树之后,浏览器会立即将其渲染出来。之后再对这个元素所做的任何修改,都会立即在浏览器中反映出来。

6.元素后代

元素可以拥有任意多个子元素和后代元素,因为元素本身也可以是其他元素的子元素。childNodes属性包含元素所有的子节点,这些子节点可能是其他元素、文本节点、注释或处理指令。不同浏览器在识别这些节点时的表现有明显不同。要取得某个元素的子节点和其他后代节点,可使用元素的getElementsByTagName()方法。在元素上调用这个方法与在文档上调用是一样的,只不过搜索范围限制在当前元素之内,即只会返回当前元素的后代。对于本节前面的例子,可以像下面这样取得其所有的元素:

let ul = document.getElementsByTagName('ul'); let items = ul.getElementsByTagName('li');

14.1.4 Text类型

Text节点由Text类型表示,包含按字面解释的纯文本,也可能包含转义后的HTML字符,但不含HTML代码。Text类型的节点具有以下特征:❑ nodeType等于3; ❑ nodeName值为”#text”;❑ nodeValue值为节点中包含的文本; ❑ parentNode值为Element对象;❑ 不支持子节点。Text节点中包含的文本可以通过nodeValue属性访问,也可以通过data属性访问,这两个属性包含相同的值。修改nodeValue或data的值,也会在另一个属性反映出来。文本节点暴露了以下操作文本的方法:❑ appendData(text),向节点末尾添加文本text; ❑ deleteData(offset, count),从位置offset开始删除count个字符;❑ insertData(offset, text),在位置offset插入text;❑ replaceData(offset, count, text),用text替换从位置offset到offset+count的文本;❑ splitText(offset),在位置offset将当前文本节点拆分为两个文本节点;❑ substringData(offset, count),提取从位置offset到offset+count的文本。除了这些方法,还可以通过length属性获取文本节点中包含的字符数量。这个值等于nodeValue. length和data.length。默认情况下,包含文本内容的每个元素最多只能有一个文本节点。

你好,世界! // 访问这个文本节点 let textNode = div.firstChild; // 或div.childNodes[0] // 取得文本节点的引用后,可以像这样来修改它: div.firstChild.nodeValue = 'some other message'; // 修改文本节点还有一点要注意, // HTML或XML代码(取决于文档类型)会被转换成实体编码,即小于号、大于号或引号会被转义, div.firstChild.nodeValue = 'some ; strong ; other ; '

这是在将HTML字符串插入DOM文档前进行编码的有效方式。

1.创建文本节点

document.createTextNode()可以用来创建新文本节点,它接收一个参数,即要插入节点的文本。跟设置已有文本节点的值一样,这些要插入的文本也会应用HTML或XML编码

2.规范化文本节点

DOM文档中经常出现两个相邻文本节点。normalize()可以合并相邻的文本节点,是在Node类型中定义的(因此所有类型的节点上都有这个方法)。在包含两个或多个相邻文本节点的父节点上调用normalize()时,所有同胞文本节点会被合并为一个文本节点,这个文本节点的nodeValue就等于之前所有同胞节点nodeValue拼接在一起得到的字符串。

3.拆分文本节点

Text类型定义了一个与normalize()相反的方法——splitText(),可在指定的偏移位置拆分nodeValue,将一个文本节点拆分成两个文本节点。这个方法返回新的文本节点,具有与原来的文本节点相同的parentNode拆分文本节点最常用于从文本节点中提取数据的DOM解析技术。

14.1.5 Comment类型

DOM中的注释通过Comment类型表示。Comment类型的节点具有以下特征:❑ nodeType等于8; ❑ nodeName值为”#comment”; ❑ nodeValue值为注释的内容; ❑ parentNode值为Document或Element对象;❑ 不支持子节点。Comment类型与Text类型继承同一个基类(CharacterData),因此拥有除splitText()之外Text节点所有的字符串操作方法。与Text类型相似,注释的实际内容可通过nodeValue或data属性获得。注释节点可以作为父节点的子节点来访问注释节点很少通过JavaScrpit创建和访问,此外,浏览器不承认结束的标签之后的注释。

14.1.6 CDATASection类型

CDATASection类型表示XML中特有的CDATA区块。CDATASection类型继承Text类型,因此拥有包括splitText()在内的所有字符串操作方法。CDATASection类型的节点具有以下特征:❑ nodeType等于4; ❑ nodeName值为”#cdata-section”;❑ nodeValue值为CDATA区块的内容; ❑ parentNode值为Document或Element对象;❑ 不支持子节点。CDATA区块只在XML文档中有效,因此某些浏览器比较陈旧的版本会错误地将CDATA区块解析为Comment或Element。在真正的XML文档中,可以使用document.createCDataSection()并传入节点内容来创建CDATA区块。

14.1.7 DocumentType类型

DocumentType类型的节点包含文档的文档类型(doctype)信息,具有以下特征:❑ nodeType等于10; ❑ nodeName值为文档类型的名称;❑ nodeValue值为null; ❑ parentNode值为Document对象;❑ 不支持子节点。DocumentType对象在DOM Level 1中不支持动态创建,只能在解析文档代码时创建。对于支持这个类型的浏览器,DocumentType对象保存在document.doctype属性中。DOM Level 1规定了DocumentType对象的3个属性:name、entities和notations。name是文档类型的名称,entities是这个文档类型描述的实体的NamedNodeMap,notations是这个文档类型描述的表示法的NamedNodeMap。因为浏览器中的文档通常是HTML或XHTML文档类型,所以entities和notations列表为空。(这个对象只包含行内声明的文档类型。)无论如何,只有name属性是有用的。这个属性包含文档类型的名称,即紧跟在



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3