原文链接:https://javascript.info/basic-dom-node-properties,translate with ❤️ by zhangbao.
让我们更深入地了解 DOM 节点。
在本章中,我们将更多地了解它们是什么以及它们最常用的属性。
DOM 节点类
DOM 节点根据其类别具有不同的属性。例如,<a>
标签对应的元素节点具有与链接相关的属性,<input>
标签对应的元素节点具有与输入相关的属性,依此类推。文本节点与元素节点不同,但是在它们之间也存在共同的属性和方法,因为所有 DOM 节点类都形成于单个层次结构。
每个 DOM 节点都属于相应的内置类。
层次结构的起点是 EventTarget,Node 继承了它,其他更具体的节点又继承自 Node
。
下面这张图片展示了刚才说的关系:
EventTarget
:根“抽象”类,无法创建实例,是作为基类使用的。所有的 DOM 节点都支持的所谓的“事件”,就是起源于它,之后会介绍。Node
:也是一个“抽象”类,作为 DOM 节点的基础,也无法创建实例。它提供了 3 大核心功能:parentNode
、previousSibling
/nextSibling
和childNodes
等(都是 getter)。它又被具体的几个类继承:代表文本节点的Text
,代表元素节点的Element
和代表注释节点的Comment
。Element
: 所有元素节点的基类。它提供了元素级别的遍历属性,像:previousElementSibling
/nextElementSibling
、children
和查找方法(像getElementsByTagName
和querySelector/querySelectorAll
)。Element
也充当SVGElement
、XMLElement
和HTMLElement
这些具体类的基类。HTMLElement
:所有 HTML 元素的基类,几乎所有的 HTML 元素都继承自它:HTMLInputElement
:<input>
元素类型,HTMLBodyElement
:<body>
元素类型,HTMLAnchorElement
:<a>
元素类型……每个标签都有自己的所属类型,以及伴随所属类型下包含的特定属性和方法
因此,一个节点所能提供的最终的完整属性和方法集,其实就是继承/叠加而来的结果。
我们以 <input>
元素为例,它属于 HTMLInputElement
类型,最终叠加到它身上的属性和方法来源自:
HTMLInputElement
:提供与输入相关的属性,继承自……HTMLElement
:提供了通用的 HTML 元素方法(getter/setter),继承自……Element
:提供了通用元素方法,继承自……Node:
提供了通用 DOM 节点属性,继承自……EventTarget
:提供了事件支持(之后讲到),……最终继承自
Object
,所以像hasOwnProperty
这样的“纯对象”上的方法在<input>
元素也有。
要查看 DOM 节点类名,我们可以回想一下,对象通常具有 constructor
属性,它指向对应的类构造器,constructor.name
的值就是构造器名称:
alert(document.body.constructor.name); // HTMLBodyElement
或者直接使用 toString()
:
alert(document.body); // [object HTMLBodyElement]
也可以使用 instanceof
检查继承关系:
alert(document.body instanceof HTMLBOdyElement); // true
alert(document.body instanceof HTMLElement); // true
alert(document.body instanceof Element); // true
alert(document.body instanceof Node); // true
alert(document.body instanceof EventTarget); // true
如你所见,DOM 节点就是一个 JavaScript 对象,JavaScript 对象采用的是基于原型的继承方式。
要在浏览器控制台中查看元素的话,可以使用 console.dir(elem)
,你会在控制台看到 HTMLElement.prototype
、Element.prototype
等对象。
console.dir(elem)
** 和 ****console.log(elem)**
的不同多数浏览器同时支持
console.dir
和console.log
方法。这两个方法都是将参数输出到控制台显示。对于普通的 JavaScript 对象来说,使用这两个方法输出,结果没有区别。但对于 DOM 元素就不同了:
console.log(elem)
现实的是元素的 DOM 树结构。
console.dir(elem)
将元素作为一个 DOM 对象显示,可以用来很方便地查看元素属性信息。不信,就在
document.body
上试试吧。
标准里的 IDL
规范中,类并不是用 JavaScript 描述的,而是用一种特殊的接口描述语言(Interface description language,IDL),它通常更容易理解。
在 IDL 中,所有属性前面代表它的数据类型。例如,
DOMString
、Boolean
等。以下是一段带注释的规范节选,描述的是
HTMLInputElement
类:```javascript // 定义 HTMLInputElement // 冒号“:”表示 HTMLInputElment 继承自 HTMLElement interface HTMLInputElement: HTMLElment { // 下面列举了 元素的属性和方法
// “DOMString”表示这些属性的属性值都是字符串 attribute DOMString accept; attribute DOMString alt; attribute DOMString autocomplete; attribute DOMString value;
// 布尔属性(true/false) attribute boolean autofocus; …
// 方法。“void”表示该方法没有返回值 void select(); … }
>
> 其他类的描述与此类型。
<a name="dd8oak"></a>
## 属性 nodeType
`nodeType` 属性是确定 DOM 节点的“类型”的经典方法。
它的属性值是一个数值:
- `elem.nodeType === 1` 表示元素节点。
- `elem.nodeType === 3` 表示文本节点。
- `elem.nodeType === 9` 表示 `document` 对象。
- 还有更多[类型](https://dom.spec.whatwg.org/#node)。
例如:
```html
<body>
<script>
let elem = document.body;
// 它是什么类型的呢?
alert(elem.nodeType); // 1 => 元素
alert(elem.firstChild.nodeType); // 3 => 文本
// document 对象对应的 nodeType 值是 9
alert(document.nodeType); // 9
</script>
</body>
在现代脚本中,我们可以使用 instanceof
和其他基于类的测试来查看节点类型,但有时 nodeType
可能更简单。 我们只能读取 nodeType
,而不能修改它。
标签名:nodeName/tagName
给定一个 DOM 节点,我们可以通过它的 nodeName
/tagName
属性获得其标签名。
例如:
alert(document.body.nodeName); // BODY
alert(document.body.tagName); // BODY
那么 tagName
和 nodeName
之间与什么区别吗?
当然,首先是不同的属性名,除此之外,还有一些微妙的差别。
tagName
只存在于Element
节点上。nodeName
则是定义在Node
上的:对于元素,
nodeName
和tagName
的返回结果是一样的。对于其他节点类型(文本、注释等),它返回节点类型的对应字符串表示(像
#text
、#comment
等)。
也就是说,tagName
是元素节点属性(源自 Element
类),而 nodeName
属性则能表示其他类型节点。
例如,下面来比较 document
和文本节点的 tagName
和 nodeName
属性。
<body><!-- 注释 -->
<script>
// 对注释
alert(document.body.firstChild.tagName); // undefiend(不是元素)
alert(document.body.firstCild.nodeName); // #comment
// 对 document
alert(document.tagName); // undefined(不是元素)
alert(document.nodeName); // #document
</script>
</body>
如果只是处理元素节点的话,使用 tagName
就行了。
tagName`` 的值总是大写的(XHTML 除外)
浏览器有两种处理文档的模式:HTML 和 XML。网页通常都是处于 HTML 模式下的;而 XML 模式,当浏览器接收网页时,接收的请求头里有 Content-Type: application/xml+xhtml``,就会启用。
浏览器有两种处理文档的模式:HTML 和 XML。 通常,HTML 模式用于网页。当浏览器收到带有标题 Content-Type: application/xml+xhtml`` 的 XML 文档时,将启用 XML 模式。
在 HTML 模式下,tagName/nodeName
总是大写的:比如,<body>
或对应 tagName/nodeName
的值都是 BODY``。在 XML 模式下,tagName/nodeName`` 的返回结果总是在文档中出现的样子,不过 XML 模式现在已经非常少使用了。
内容:innerHTML
innerHTML
属性允许将元素内的 HTML 作为字符串获取。
我们也可以修改它,所以这是改变页面的最有效方法之一。
下例中,先显示了 document.body
的内容,然后再完全替换它:
<body>
<p>一个自然段</p>
<div>一个 div</div>
<script>
alert(document.body.innerHTML); // 获取当前内容
document.body.innerHTML = '新内容'; // 替换原本内容
</script>
</body>
当我们使用 innerHTML
插入无效文本时,浏览器也会自己修复:
<body>
<script>
document.body.innerHTML = '<b>test'; // 忘记加 </b> 了
alert(document.body.innerHTML); // <b>test</b>(修复后)
</script>
</body>
脚本不会执行
当使用 innerHTML 向文档插入