灏天阁

HTML DOM

· Yin灏
构造器 父级构造器 Core或HTML 说明
Node Core DOM 树上所有的节点都属于 Node
Document Node Core Document 对象,主要用于表示 XML 文档项目
HTMLDocument Document HTML 即 window.document 或简写 document 所指向的对象
Element Node Core 在源文档中,每一个标签都是一个元素
HTMLElement Element HTML 这是一个通用性的构造器,所有与 HTML 元素有关的构造器都继承于该对象
HTMLBodyElement HTMLElement HTML 用于表示 <body> 标签的元素
HTMLLinkElement HTMLElement HTML 代表一个 A 元素
其他构造器 HTMLElement HTML 剩下所有 HTML 页面元素
CharacterData Node Core 文本处理类的通用性构造器
Text CharacterData Core 即插入到标签中的文本节点
Comment CharacterData Core <!--HTML注释-->
Attr Node Core 用于代表各标签中的属性,例如在代码 <p id="closer"></p> 中,属性 id 也是一个 DOM 对象,由 Attr() 负责处理
NodeList Core 即节点列表,是一个用于存储对象,拥有自身 length 属性的类数组对象
NameNodeMap Core 其功能与上一个相同,不同之处在于,该对象中的元素是通过对象名而不是数字索引来访问的
HTMLCollection Core 其功能与前两个对象相似,但它是为 HTML 特性量身定制的

DOM 节点的访问

  1. 文档节点
// 控制台输入
console.dir(document);

在 DOM 中,节点类型有 12 种,每种类型分别用一个整数来表示,常用的如下:

  • document 的节点类型:9
  • 元素的节点类型:1
  • 属性的节点类型:2
  • 文本的节点类型:3

另外,节点也各自有各自的名称,对于文本节点,其名字就是 #text,document 节点的名字是 #document (document.nodeName)

同时节点也都有各自的节点值,例如,文本节点的值就是它的实际文本,但 document 节点中却不包含任何值 document.nodeValue (null)

  1. documentElement

documentElement 表示根节点 <html></html>

document.documentElement; // <html></html>
document.documentElement.nodeType; // 1 (元素类节点)

对于元素类节点来说,其 nodeName 和 tagName 属性就等于该标签本身的名字

document.documentElement.nodeName; // 'HTML'
document.documentElement.tagName; // 'HTML'
  1. 子节点

如果要检查一个节点是否含有子节点,可以调用 hasChildNodes() 方法

document.documentElement.hasChildNodes(); // true

HTML 元素有三个子节点 - head、body以及两者之间的空白 (大多数浏览器都会将空白算在内,但不是所有浏览器都如此),我们可以通过该元素的 childNodes 这个类似于数组的集合来访问它们。

document.documentElement.childNodes.length; // 3
document.documentElement.childNodes[0]; // <head>...</head>
document.documentElement.childNodes[1]; // #text
document.documentElement.childNodes[2]; // <body>...</body>

任何节点都可以通过其自身的 parentNode 属性来访问它的父节点

document.documentElement.childNodes[1].parentNode; // <html>...</html>
<!doctype html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <title>title</title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link rel="stylesheet" href="./css/index.css">
    <script defer src="./js/index.js"></script>
</head>

<body>
    <p class="opener">first paragraph</p>
    <p><em>second</em> paragraph</p>
    <p id="closer">final</p>
    <!-- and that's about it -->
</body>

</html>
var bd = document.documentElement.childNodes[2];
console.log(bd); // <body>...</body>
console.log(bd.childNodes.length); // 9

/*
    NodeList(9) [text, p.opener, text, p, text, p#closer, text, comment, text]
        0: text
        1: p.opener
        2: text
        3: p
        4: text
        5: p#closer
        6: text
        7: comment
        8: text
        length: 9
        [[Prototype]]: NodeList
*/
  1. 属性
bd.childNodes[1]; // <p class="opener">first paragraph</p>

// 检查是否存在属性
bd.childNodes[1].hasAttributes(); // true

// 检查有几个属性
bd.childNodes[1].attributes; // NamedNodeMap {0: class, class: class, length: 1}
bd.childNodes[1].attributes.length; // 1

// 获取属性名
bd.childNodes[1].attributes[0].nodeName; // 'class'
// 获取属性值
bd.childNodes[1].attributes[0].nodeValue; // 'opener'
bd.childNodes[1].attributes['class'].nodeValue; // 'opener'

bd.childNodes[1].getAttribute('class'); // 'opener'
  1. 访问标签中的内容
bd.childNodes[1].nodeName; // 'P'
bd.childNodes[1].textContent; // 'first paragraph'
bd.childNodes[1].innerText; // 'first paragraph'
bd.childNodes[1].innerHTML; // 'first paragraph'
  1. DOM 访问的快捷方法
document.getElementsByTagName('p').length; // 3
document.getElementsByTagName('p')[0]; // <p class="opener">first paragraph</p>
// 获取元素 id
document.getElementsByTagName('p')[2].id; // 'closer'
// 获取 class 名称
document.getElementsByTagName('p')[0].className; // 'opener'
// 获取页面所有元素
document.getElementsByTagName('*').length
// id
document.getElementById('closer');

还支持其他方法:

  • getElementByClassName()
  • querySelector()
  • querySelectorAll()
  1. 兄弟节点、body元素及首尾子节点
  • nextSibling
  • previousSibling
var para = document.getElementById('closer');

console.log(para.nextSibling); // #text
console.log(para.previousSibling); // #text
console.log(para.previousSibling.previousSibling); // <p></p>
console.log(para.previousSibling.previousSibling.previousSibling); // #text
console.log(para.previousSibling.previousSibling.nextSibling.previousSibling); // <p></p>

对于 body 元素来说,下面是一些常用的快捷方式:

document.body; // <body></body>
document.body.nextSibling; // null
document.body.previousSibling; // <head></head>

另外 firstChild / lastChild,

  • firstChild 等价于 childNodes[0]
  • lastChild 等价于 childNodes[childNodes.length - 1]
document.body.firstChild;
document.body.lastChild;
document.body.lastChild.previousSibling;
document.body.lastChild.previousSibling.nodeValue;
  1. 遍历 DOM
function walkDOM(n) {
    do {
        console.log(n)
        if (n.hasChildNodes()) {
            walkDOM(n.firstChild);
        }
    } while (n = n.nextSibling);
}

walkDOM(document.documentElement)

DOM 节点的修改

  1. 修改样式
my.style.border = "1px solid red";
my.style.fontWeight = 'bold';

通过 style 的 cssText 属性,将 CSS 样式当做字符串处理

my.style.cssText; // "border: 1px solid red; font-weight: bold"
// 修改
my.style.cssText += " border-style: dashed"

新建节点

var myp = document.createElement('p');
myp.innerHTML = 'yet another';
myp.style.border = '2px dotted blue';
document.body.appendChild(myp);
纯净DOM
var myp = document.createElement('p');
var myt = document.createTextNode('one more paragraph');
myp.appendChild(myt);
var str = document.createElement('strong');
str.appendChild(document.createTextNode('bold'));
myp.appendChild(str);
document.body.appendChild(myp);
cloneNode()
  • true: 深拷贝,包括所有自己点
  • false: 浅拷贝,只针对当前节点
insertBefore()

将新元素插入到指定元素的前面

document.body.insertBefore(
    document.createTextNode('boo!'), 
    document.body.firstChild
)

移除节点

要想从 DOM 树汇总移除一个节点,我们可以调用 removeChild()

var myp = document.getElementsByTagName('p')[1];
// 如果稍后还需要用到被移除的节点的话,可以保存该方法的返回值
var removed = document.body.removeChild(myp);
console.log(removed); // <p>...</p>
conosole.log(removed.firstChild); // <em>...</em>

此外,还有一个 replaceChild() 方法,该方法可以在移除一个节点的同时将另一个节点放在该位置。

var p = document.getElementsByTagName('p')[1]; // <p id="closer">final</p>
// 返回被移除节点的引用,<p id="closer">final</p>
var replaced = document.body.replaceChild(removed, p); // 

如果我们想将某个子树中的内容一并抹去的话,

document.body.innerHTML = ''; // 最快捷的方式

下面方法用于删除某个指定节点所有子节点的函数:

function removeAll(n) {
    while(n.firstChild) {
        n.removeChild(n.firstChild)
    }
}
removeAll(document.body)

只适用于 HTML 的 DOM 对象

  1. 访问文档的基本方法
  • document.images: 当前页面中所有图片的集合
  • document.links: 当前页面中所有A标签的集合
  • document.forms: 当前页面中所有表单的集合
/*
 <form action="">
    <p>姓名</p>
    <input type="text" name="username" />
    <p>密码</p>
    <input type="text" name="password" />
    <textarea></textarea>
    <select>
        <option value="1">1</option>
    </select>
</form>
*/
console.log(document.forms[0].elements); // HTMLFormControlsCollection(4) [input, input, textarea, select]
console.log(document.forms[0].elements[0].value);
document.forms[0].elements[0].value = 'first input';
document.forms[0].elements[0].disabled = true;

// 如果 form 本身或 form 的元素拥有 name 属性的话,也可以通过 name 名来访问
document.forms[0].elements['username'];
document.forms[0].elements.username;

- Book Lists -