基本DOM操作

104 阅读4分钟

基本DOM 操作


作者:©endless

1、Dom 介绍

Dom 表示由多层节点构成的文档 例如下面的 HTML 文档

<html>
    <head>
        <title>Sample Page</title>
    </head>
    <body>
        <p>Hello World!</p>
    </body>
</html>

其文档结构如下图所示:

Dom结构.excalidraw.png 所以对于 dom 树的操作实际上是对各个节点的操作。

所有节点继承自node类型,其共有12个类型,常用的主要有以下几个类型:

常量描述
Node.ELEMENT_NODE1元素节点、例如 <div>、<p>
Node.TEXT_NODE3Element中的实际文字
Node.COMMENT_NODE8Comment节点,表示注释
Node.DOCUMENT_NODE9文档,在浏览器中表示页面
Node.DOCUMENT_FRAGMENT_NODE11轻量文档,在上面的 Dom 操作不会触发重绘

其余的节点类型可以自行查阅 MDN

2、Dom 操作

1、节点关系

NodeList

每个节点都有一个 childNodes 属性,其中包含一个 NodeList 的实例。NodeList 是一个类数组 对象,用于存储可以按位置存取的有序节点。

注意:Dom 结构的变化会自动反应在NodeList

假设有如下文档结构:

<body>
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>4</div>
</body>

获取到 body 下的NodeList:

let childList = document.body.childNodes; 
// NodeList(5) [div, div, div, div, text]
// 有 text 节点,说明 childNodes 会把所有节点查询出来

body添加一个节点:

let div = document.createElement('div');
div.textContent='5';
document.body.appendChild(div);

这时来打印一下 childList

console.log(childList);
// NodeList(6) [div, div, div, div, text, div]
// 可以看出来 childList 会根据 dom 结构实时变化

相关 API

属性

firstChild: 第一个子节点

lastChild: 最后一个子节点

previousSibling: 前一个兄弟节点

nextSibling: 后一个兄弟节点

parentNode: 父节点

方法

hasChildNodes(): 返回 true 说明节点有一个或多个子节点

2、操作节点

appendChild(): 在 childNodes末尾添加节点,如果是已经存在的节点,会转移到新的位置

insertBefore(): 插入指定位置,接收两个参数:要插入的节点和参照节点,参照节点为null时,插入最后

replaceChild(): 替换节点,接收两个参数:要插入的节点和要替换的节点

removeChild(): 移除节点

clone(): 复制节点,传 true 为深拷贝,会包含复制节点和整个子dom树,false为浅拷贝,只包含复制节点

3、定位节点

getElementById(): 通过 id 获取节点

getElementsByTagName(): 通过标签名获取,返回的是HTMLCollection

4、获取属性

getAttribute(): 获得对应属性

setAttribute(): 设置对应属性

removeAttribute(): 移除对应属性

5、创建节点

createElement(): 创建新元素

3、Dom 扩展

1、Selectors API

querySelector(): 返回匹配该模式的第一个后代元素

querySelectorAll(): 返回所有匹配的节点,返回一个NodeList静态实例

matches(): 如果元素匹配css选择符返回 true,否则返回 false。

2、元素遍历

这几个 API 跟上面类似,但不会再包含文本和注释了。

childElementCountfirstElementChildlastElementChildpreviousElementSiblingnextElementSibling

3、H5 新出的一些方法

getElementsByClassName(): 返回对应类名元素的NodeList

classList: 包含 4 个方法

  • add(): 向类名列表中添加指定的字符串值 value。如果这个值已经存在,则什么也不做

  • contains(): 返回布尔值,表示给定的 value 是否存在

  • remove(): 从类名列表中删除指定的字符串值 value

  • toggle(): 如果类名列表中已经存在指定的 value,则删除;如果不存在,则添加

innerHTML: 插入标记

outerHTML:返回字符串,写入时,会替代调用它的元素

children: 返回只包含元素的 Element 类型的子节点

4、example

下面通过一个例子来对 Dom 操作的 API 进行练习,练习中会尽量把所有 API 都用进去。

对于一个初始的HTML文档

// index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dom 操作练习</title>
</head>
<body>
</body>
</html>

首先引入scriptstyle

// index.html
<body>
  <script>
    let link = document.createElement('link');
    link.rel = "stylesheet";
    link.type = "text/css";
    link.href = "./index.css"
    document.head.appendChild(link);
    let script = document.createElement('script');
    script.src = "./index.js";
    document.body.appendChild(script);
  </script>
</body>

这时的HTML文档如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dom 操作练习</title>
    <link rel="stylesheet" type="text/css" href="./index.css">
</head>
<body>
  	<script>...</script>
    <script src="./index.js"></script>
</body>
</html>

然后将导入scriptstyle的代码去掉

// index.js
document.body.removeChild(
    document.body.querySelector('script')
)

body中插入一个div

let div = document.createElement('div');
div.appendChild(document.createTextNode('a temp div'));
document.body.insertBefore(
    div,
    document.body.getElementsByTagName('script')[0]
)

将插入的div替换掉,这里使用 innerHTMLouterHTML

innerHTML方式:

let tempDiv =  document.body.querySelector('div');
tempDiv.innerHTML = `
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>4</div>
    <div>5</div>
`;

outerHTML方式:

tempDiv.outerHTML = `
    <div>
        <div>1</div>
        <div>2</div>
        <div>3</div>
        <div>4</div>
        <div>5</div>
    </div>
`;

为每个div添加样式并设置id

// 最外层的 div 添加 container 类
document.body.children[0].classList.add('container');
// 内层 div 每个都添加 box 类
let nodeList = document.querySelector('div.container').children;
let len = document.querySelector('div.container').childElementCount;
for(let i = 0; i < len; ++i) {
    nodeList[i].classList.add('box');
  	nodeList[i].setAttribute('id', i+1);
}

删除 idbox3的节点

document.querySelector('div.container').removeChild(
    document.body.querySelector("#box4").previousElementSibling
)

最后:

熟能生巧、多看文档、多练习