💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] ## 9.1 节点层次 DOM可以将任何HTML文档描绘成一个由**多层节点**构成的结构。节点分为不同的类型,拥有个自己的特点、数据和方法,表示不同的信息及(或)标记。 节点之间的关系构成了层次,而所有页面标记则表现为一个以特定节点为根节点的**树形结构**。 例如:![](https://box.kancloud.cn/0af8d7484f4f056b2573203f026a3444_486x266.png) ### 9.1.1 Node类型 DOM1级定义了一个`Node`接口,该接口将由DOM中的所有节点类型实现。这个Node接口在JavaScript中是作为Node类型实现的。除了IE之外,在其他所有浏览器中都可以访问到这个类型。**JavaScript中的所有节点类型都继承自Node类型**,因此所有节点类型都**共享着相同的基本属性和方法**。 **了解节点的具体信息,可以使用`nodeName和nodeValue`属性** ||| |---|---| |元素节点  | Node.ELEMENT_NODE(1)| |属性节点  | Node.ATTRIBUTE_NODE(2)| |文本节点  | Node.TEXT_NODE(3)| |CDATA节点 | Node.CDATA_SECTION_NODE(4)| |实体引用名称节点 |   Node.ENTRY_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)| |DTD声明节点 | Node.NOTATION_NODE(12)| **1.节点关系** 节点树中的节点彼此拥有**层级**关系。 父(parent)、子(child)和同胞(sibling)等术语用于描述这些关系。父节点拥有子节点。同级的子节点被称为同胞(兄弟或姐妹)。 * 在节点树中,顶端节点被称为根(root) * 每个节点都有父节点、除了根(它没有父节点) * 一个节点可拥有任意数量的子节点 * 同胞是拥有相同父节点的节点 ![](https://box.kancloud.cn/650369666614cdf7ee1880b6bfd4ab85_801x421.png) 每个节点都有一个`childNodes`属性,其中保存着一个`NodeList`对象。NodeList是一种类数组对象,用于保存一组有序的节点,可以通过位置来访问这些节点。 **访问保存在NodeList中的节点** ~~~ var firstChild = someNode.childNodes[0]; var secondChild = someNode.childNodes.item(1); var count = someNode.childNodes.length; ~~~ * `childNodes`属性访问更方便; * `hasChildNodes()`在节点包含一或多个子节点的情况下返回true,比查询childNodes列表的length属性更简单; * 所有节点都有一个`ownerDocument`属性,指向表示整个文档的文档节点。这种关系表示的是任何节点都属于它所在的文档,任何节点都不能同事存在于两个或更多个文档中。 **2.操作节点** ||| |---|---| | appendChild(newNode) | 向childNodes列表的末尾添加一个节点,返回新增的节点| | insertBefore(newNode , referNode) | 向childNodes列表特定位置添加一个节点,返回新增的节点 | | replaceChild(newNode,repNode) | 替换childNodes列表中的某个节点,返回替换新节点 | | removeChild(node)| 移除节点,返回被移除的点| 以上方法操作的都是某个节点的子节点,必须先取得父节点,然而并不是所有类型的节点都有子节点,不支持子节点的节点上调用会导致错误。 **3.其他方法** ||| |---|---| | cloneNode() | 创建调用这个方法的节点的一个完全相同的副本,接受一个boolean参数,表示是否执行深复制(复制节点及其子节点树)。复制后返回的节点副本属于文档所有,没有父节点。| | insertBefore(newNode , referNode) | 向childNodes列表特定位置添加一个节点,返回新增的节点 | | normalize() | 移除空的文本节点,并合并相邻的文本节点。 ### 9.1.2 Document类型 JavaScript通过**Document类型**表示文档。在浏览器中,document对象是HTMLDocument的一个实例,表示整个HTML页面。 document对象是window对象的一个属性,因此可以将其作为全局对象来访问。 Document节点特征: * nodeType的值为9; * nodeName的值为"#document"; * nodeValue的值为null; * parentNode的值为null; * ownerDocument的值为null; * 其子节点DocumentType(最多一个)、Element(最多一个)、 ProcessingInstruction Comment **Document类型可以表示HTML页面,但更常作为HTMLDocument实例的document对象,取得与页面有关的信息,操作页面外观及其底层结构。** **1.文档的子节点** | 属性 | 描述 | | --- | --- | | documentElement | 始终指向HTML页面中的`<html>`属性 。 | | body | 直接指向`<body>`元素。 | |doctype | 指向子节点DocumentType 。| **2.文档信息** 作为HTMLDocument的一个实例,document对象还有一些属性,表示网页的一些信息。 | 属性 | 描述 | | --- | --- | | title |包含<title>元素中的文本 | | URL | 包含页面完整的URL(地址栏中显示的地址) | | domain | 只包含页面的域名 | | referrer | 包含链接到当前页面的那个页面的URL,无来源则为空字符串 | **3.查找元素** | 方法 | 描述 | | --- | --- | | getElementById(id) | 找到与id匹配(大小写)的元素并返回。*同名返回第一个* | | getElementsByTagName(tag) | 取得元素的标签名,返回包含零或多个元素的NodeList。HTML文档中,返回一个HTMLCollection对象(动态的集合)。可以通过namedItem(name)取得集合中name特性的项。 | | getElementsByName(name) | 返回带有给定name特性的所有元素。 | **4.特殊集合** document对象还有一些特殊的集合,都是HTMLCollection对象。 | 对象集合| | 描述 | | --- | --- | | anchors | 返回文档中所有带name特性的`<a>`元素。| | forms | 返回文档中所有的`<form>`元素。| | images | 返回文档中所有的`<img>`元素。| | links | 返回文档中所有带href特性的`<a>`元素。| **5.文档写入** | 方法| | 描述 | | --- | --- | | write(str) | 向文档写入文本。| | writeln(str)| 写入文本后添加`\n`换行符。| | open() | 打开一个流,以收集来自任何` document.write()` 或 `document.writeln()` 方法的输出。| | close() | 关闭用 `document.open() `方法打开的输出流,并显示选定的数据。| **6. 文档元素属性** 所有文档元素都有下面的属性: * clientWidth、clientHeight clientHeight 属性返回元素节点可见部分的高度, clientWidth属性返回元素节点可见部分的宽度。 所谓“可见部分”,指的是不包括溢出(overflow)的大小,只返回该元素在容器中占据的大小,对于有滚动条的元素来说,它们等于滚动条围起来的区域大小。 这两个属性的值不包括滚动条、边框和Margin,只包含内容和它的内边距,单位为像素。 对于整张网页来说,当前可见高度(即视口高度)要从document.documentElement对象上获取,等同于window.innerHeight属性减去水平滚动条的高度。 没有滚动条时,这两个值是相等的;有滚动条时,前者小于后者。 ~~~ var rootElement = document.documentElement; // 没有水平滚动条时 rootElement.clientHeight === window.innerHeight // true // 没有垂直滚动条时 rootElement.clientWidth === window.innerWidth // true ~~~ 对于`<i>、<code>和<span>`这些内联元素,clientWidth和clientHeight总是0 * clientLeft、clientTop clientLeft 属性等于元素节点左边框(left border)的宽度, clientTop属性等于网页元素顶部边框的宽度,单位为像素。 但是如果元素有滚动条,并且浏览器将这些滚动条放置在左侧或顶部(极少见),这两个属性就包括了滚动条的宽度,但不包括Margin和Padding。 如果元素是内联元素,clientLeft和clientTop属性总是为0。 * scrollWidth、scrollHeight scrollHeight属性返回某个网页元素的总高度, scrollWidth 属性返回总宽度,也就是元素的内容加上它的内边距再加上任何溢出内容的尺寸。这两个属性是只读属性。 它们返回的是整个元素的高度或宽度,包括由于存在滚动条而不可见的部分。默认情况下,它们包括Padding,但不包括Border和Margin。 * scrollLeft、scrollTop scrollLeft属性表示网页元素的水平滚动条向右侧滚动的像素数量, scrollTop 属性表示网页元素的垂直滚动条向下滚动的像素数量。对于那些没有滚动条的网页元素,这两个属性总是等于0。 如果要查看整张网页的水平的和垂直的滚动距离,要从document.body元素上读取。 document.body.scrollLeft document.body.scrollTop 这两个属性都可读写,设置该属性的值,会导致浏览器将指定元素自动滚动到相应的位置。 * offsetWidth、offsetHeight offsetHeight 属性返回元素的垂直高度,offsetWidth 属性返回水平宽度。这两个属性值包括Padding和Border、以及滚动条,也就是说从边框的左上角开始计算,这也意味着,offsetHeight只比clientHeight少了边框的高度。它们的单位为像素,都是只读。 整张网页的高度,可以在document.documentElement和document.body上读取。 // 网页总高度 document.documentElement.offsetHeight document.body.offsetHeight // 网页总宽度 document.documentElement.offsetWidth document.body.offsetWidth * offsetLeft、offsetTop offsetLeft 返回当前元素左上角相对于 offsetParent节点的垂直偏移, offsetTop 返回水平位移,单位为像素。通常,这两个值是指相对于父节点的位移。 ### 9.1.3 Element类型 Element类型用于表现XML或HTML元素,提供了**对元素标签名、子节点及特性的访问**。 **Element节点特征:** * nodeType的值为1; * nodeName的值为元素的标签名; * nodeValue的值为null; * parentNode可能是Document或Element; * 其子节点可能是Element、Tex、Comment、ProcessingInstruction、CDATASection或EntityReference。 可以使用nodeName属性或tagName属性访问元素的标签名。 在HTML中,标签名始终都以全部大写表示,推荐:`element.tagName.toLowerCase() //获取标签` **1.HTML元素** 所有HTML元素都由HTMLElement类型或它的子类型来表示。HTMLElement类型直接继承自Element并添加了一些属性,分别对应于每个HTML元素中都存在的标准特性。 | 特性 | 描述 | | --- | --- | | id | 元素在文档中的唯一标识符。| | title| 有关元素的附加标题说明信息。| | lang | 元素内容的语言。| | dir | 语言的方向。(ltr为从左到右)| | className | 与元素的class特性对应,为元素指定的CSS类。| **2.取得特性** 每个元素都有一或多个特性,这些特性的用途是给出相应元素或其内容的附加信息。 `getAttribute(attr)`:返回指定特性的值。给定特性不存在则返回null,还可以获取自定义特性的值(html5规范自定义特性加上data-前缀以便验证) 任何元素的所有**公认(非自定义的)特性**都可以通过**DOM元素**本身的属性来访问。 有两类特殊的特性,虽然有对应的属性名,但属性的值与通过`getAttribute(attr)`返回的值并不相同: * style:get返回CSS文本;属性访问返回一个对象。 * onclick:get返回相应代码的字符串;属性访问返回一个JavaScript函数(未指定返回null)。 **3.设置特性** setAttribute(attr,attrValue):替换现在指定特性的值,若不存在,则创建改属性并设置相应的值。 通过setAttribute()方法既可以操作HTML特性也可以操作自定义特性。设置的特性名会被统一转换为小写形式。 注意:为DOM元素添加自定义的属性,该属性不会自动成为元素的特性。 ~~~ div.mycolor = "red", aler(div.getAttribute("mycolor")); //null ~~~ removeAttribute(attr):彻底删除元素的特性,不仅特性的值,还包括特性本身。 **4.attributes属性** Element类型是使用attributes属性的**唯一**一个DOM节点类型。attributes属性中包含一个`NamedNodeMap`,是一个动态的集合。 元素的每一个属性都由一个**Attr节点**表示,每个节点都保存在`NamedNodeMap对象`中。 NamedNodeMap对象方法 | 方法 | 描述 | | --- | --- | | getNamedItem(name) | 返回nodeName属性等于name 的节点。| | removeNameItem(name) | 从列表中移除nodeName属性等于name的节点。| | setNamedItem(node) | 向列表中添加节点,以节点的nodeName属性为索引。| | item(pos) | 返回位于数字pos位置处的节点。| attributes属性中包含一系列节点,每个节点的nodeName就是特性名称,而节点的nodeValue就是特性的值。 **5.创建元素** `document.createElement()`方法可以创建新元素。这个方法值接受一个参数,即要创建元素的标签名(HTML不区分大小写)。 使用createElement()方法创建新元素的同时,也为新元素设置了ownerDocument属性,此时还可以操作元素的特性,为它添加更多子节点,以及执行其他操作。 需要使用节点操作方法把新元素添加到文档树中,浏览器才会呈现改元素。 **6.元素的子节点** 元素可以有任意数目的子节点和后代节点。元素的childeNodes属性中包含了它的`所有子节点`,这些子节点有可能是元素、文本节点、注释或处理指令。 不同节点看待节点层次会有所不同。 元素也支持getElementsByTagName()方法,搜索起点是当前元素,只返回当前元素的直接后代元素。 ### 9.1.4 Text类型 文本节点有Text类型表示,包含的是可以照字面解释的**纯文本内容**(可以包含转义后的HTML字符,但不包含代码)。 Text节点特征: * nodeType的值为3; * nodeName的值为“#text"; * nodeValue的值为节点所包含的文本; * parentNode是一个Element; * 不支持(没有)子节点。 可以通过nodeValue属性或data属性访问Text节点中包含的文本。 length属性:保存着节点中字符的数目。 操作文本的方法: | 方法 | 描述 | | --- | --- | | 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为止处的字符串。 | 获取文本节点的引用后,如果文本节点存在于文档树中,修改节点的结果会立即反映,修改后字符串会经过HTML编码(如符号会被转义)。 **1.创建文本节点** document.createTextNode(text):创建文本节点,文本会按照HTML格式编码。 ~~~ var element = document.createElement("div"); element.className = "message"; var textNode = document.createTextNode("Hello world!"); element.appendChild(textNode); document.body.appendChild(element); ~~~ **2.规范化文本节点** DOM文档中存在相邻的同胞文本节点容易导致混乱,使用由`Node类型定义的normalize()方法`可以将所有文本节点合并成一个节点。 ### 9.1.5 Comment类型 注释在DOM中是通过Comment类型来表示的。 Comment节点特征: * nodeType的值为8; * nodeName的值为“#comment"; * nodeValue的值为注释的内容; * parentNode可能是Document或Element; * 不支持(没有)子节点。 Comment类型与Text类型继承自相同的鸡肋,拥有出splitText()之外的所有字符串操作方法。 ### 9.1.6 Attr类型 元素的特性在DOM中以Attr类型来表示。从技术角度,特性就是存在于元素的attributes属性中的节点。 Attr类型特征: * nodeType的值为2; * nodeName的值为特性的名称; * nodeValue的值为特性的值; * parentNode为null; * HTML中不支持(没有)子节点。 Attr对象有3个属性:name、value和specified。name是特性名称,value是特性的值,specified是一个布尔值,用以区别特性是在代码中指定的,还是默认的。 `document.createAttribute()方法`可以创建新的特性节点。 ~~~ var attr = document.createAttribute("align"); attr.value = "left"; element.setAttributeNode(attr); alert(element.attribute["align"].value); //"left" alert(element.attributeNode("align").value); //"left" ~~~