Element 类型是唯一使用 attributes 属性的 DOM 节点类型。attributes 属性包含一个NamedNodeMap 实例,是一个类似 NodeList 的“实时”集合。元素的每个属性都表示为一个 Attr 节
点,并保存在这个 NamedNodeMap 对象中。NamedNodeMap 对象包含下列方法:
removeNamedItem(name),删除 nodeName 属性等于 name 的节点;
setNamedItem(node),向列表中添加 node 节点,以其 nodeName 为索引;
item(pos),返回索引位置 pos 处的节点。
attributes 属性中的每个节点的 nodeName 是对应属性的名字,nodeValue 是属性的值。比如,要取得元素 id 属性的值,可以使用以下代码:
下面是使用中括号访问属性的简写形式:
同样,也可以用这种语法设置属性的值,即先取得属性节点,再将其 nodeValue 设置为新值,如下所示:
removeNamedItem()方法与元素上的 removeAttribute()方法类似,也是删除指定名字的属性。
下面的例子展示了这两个方法唯一的不同之处,就是removeNamedItem()返回表示被删除属性的Attr节点:
setNamedItem()方法很少使用,它接收一个属性节点,然后给元素添加一个新属性,如下所示:
一般来说,因为使用起来更简便,通常开发者更喜欢使用 getAttribute()、removeAttribute()和 setAttribute()方法,而不是刚刚介绍的 NamedNodeMap 对象的方法。
attributes 属性最有用的场景是需要迭代元素上所有属性的时候。这时候往往是要把 DOM 结构序列化为 XML 或 HTML 字符串。比如,以下代码能够迭代一个元素上的所有属性并以 attribute1=
“value1” attribute2="value2"的形式生成格式化字符串:
let pairs = [];
for (let i = 0, len = element.attributes.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 中的顺序一致。
创建元素
可以使用 document.createElement()方法创建新元素。这个方法接收一个参数,即要创建元素的标签名。在 HTML 文档中,标签名是不区分大小写的,而 XML 文档(包括 XHTML)是区分大小写的。要创建
使用 createElement()方法创建新元素的同时也会将其 ownerDocument 属性设置为 document。
此时,可以再为其添加属性、添加更多子元素。比如:
div.className = "box";
在新元素上设置这些属性只会附加信息。因为这个元素还没有添加到文档树,所以不会影响浏览器显示。要把元素添加到文档树,可以使用 appendChild()、insertBefore()或 replaceChild()。
比如,以下代码会把刚才创建的元素添加到文档的元素中:
元素被添加到文档树之后,浏览器会立即将其渲染出来。之后再对这个元素所做的任何修改,都会立即在浏览器中反映出来。
元素后代元素可以拥有任意多个子元素和后代元素,因为元素本身也可以是其他元素的子元素。childNodes属性包含元素所有的子节点,这些子节点可能是其他元素、文本节点、注释或处理指令。不同浏览器在识别这些节点时的表现有明显不同。比如下面的代码:
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
在解析以上代码时,
- 元素会包含 7 个子元素,其中 3 个是
- 元素,还有 4 个 Text 节点(表示
- 元素周围的空格)。如果把元素之间的空格删掉,变成下面这样,则所有浏览器都会返回同样数量的子节点:
所有浏览器解析上面的代码后,
- 元素都会包含 3 个子节点。考虑到这种情况,通常在执行某个操作之后需要先检测一下节点的 nodeType,如下所示:
if (element.childNodes[i].nodeType == 1) {
// 执行某个操作
}
}
以上代码会遍历某个元素的子节点,并且只在 nodeType 等于 1(即 Element 节点)时执行某个操作。
要取得某个元素的子节点和其他后代节点,可以使用元素的 getElementsByTagName()方法。在元素上调用这个方法与在文档上调用是一样的,只不过搜索范围限制在当前元素之内,即只会返回当前元素的后代。对于本节前面
- 的例子,可以像下面这样取得其所有的
- 元素:
let items = ul.getElementsByTagName("li");
这里例子中的
- 元素只有一级子节点,如果它包含更多层级,则所有层级中的
- 元素都会返回。