JavaScript DOM
基础知识
在书写Js
代码之前,一般都会先将HTML
代码书写好。
DOM
的全称为Document Object Model
即为文档对象模型。
DOM
支持将HTML
文档转换为Js
的对象进行操作。
文档渲染
浏览器会将HTML
文本内容进行渲染,并生成相应的Js
对象,同时会对不符合规则的标签进行处理。
标签修复
当一个文本只有一段文字而没有任何标签时,浏览器会自动修复,将这段文字放入<body>
标签中。
hello,world
表格处理
表格<tabel>
中不允许有内容,浏览器在渲染过程中会进行处理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<table>
放出去吧
<tbody>
<tr>
<td>hello,world</td>
</tr>
</tbody>
</table>
</body>
</html>
标签移动
所有的内容都要写在<body>
标签中,下面的例子<script>
标签写在了<body>
标签下方,在渲染时浏览器会自动对它进行移动处理。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>hello,world</h1>
</body>
<script>
document.querySelector("h1").style.backgroundColor = "red";
</script>
</html>
操纵时机
浏览器的渲染是自上而下,所以我们在对元素节点进行操纵时应当将<script>
标签放在<body>
尾步。
如果放在头部将会导致无法读取到节点对象。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
document.querySelector("h1").style.backgroundColor = "red";
</script>
<h1>hello,world</h1>
</body>
</html>
异步处理
如果非要将<script>
标签放在上面,可以使用setTimeout
来进行异步处理,它会让<script>
中代码执行排在同步渲染任务之后。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
setTimeout(() => {
document.querySelector("h1").style.backgroundColor = "red";
});
</script>
<h1>hello,world</h1>
</body>
</html>
onload
也可以对window
对象使用onload
进行事件绑定,onload
事件是指目标渲染完成后自动触发的事件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
window.onload = () => {
document.querySelector("h1").style.backgroundColor = "red";
}
</script>
<h1>hello,world</h1>
</body>
</html>
defer属性
将Js
代码放入一个外部文件中再使用<script>
进行引入。
对引入的<script>
标签设置defer
属性后,该<script>
标签会延迟加载。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="./test.js" defer></script>
<h1>hello,world</h1>
</body>
</html>
节点对象
HTML
文档中的任何内容在Js
中统称为DOM
节点对象Node
,既然是对象就包括操纵node
的属性和方法。
所有的
Node
共有12种类型常用根节点为
document
,标签元素节点,文本节点,注释节点节点继承自
Node
类型,所以有用相同的属性与方法
document
是DOM
操作的起点。
节点类型 | 类型代号 |
---|---|
元素节点 | 1 |
属性节点 | 2 |
文本节点 | 3 |
CDATA节点 | 4 |
实体引用名称节点 | 5 |
实体名称节点 | 6 |
处理指令节点 | 7 |
注释节点 | 8 |
文档节点 | 9 |
文档类型节点 | 10 |
文档片段节点 | 11 |
DTD声明节点 | 12 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<main id="main">
<!-- 注释节点 --></main>
</body>
<script>
console.log(document.body.nodeType); // 1 body标签,标签节点
let main = document.getElementById("main");
console.log(main.attributes[0].nodeType); // 2 main标签的id属性也是一个节点。属性节点
console.log(main.firstChild.nodeType); // 3 main标签下的第一个子标签 即空白行。文本节点
console.log(main.lastChild.nodeType); // 8 main标签下的最后一个子标签 即注释行。 注释节点
console.log(document.nodeType); // 9 document也是一个节点。文档节点
console.log(document.childNodes.item(0).nodeType); // 10 文档类型节点
</script>
</html>
原型链
对每一种类型的节点进行原型链的攀升,可得到如下结论。
原型 | 说明 |
---|---|
Object | 根对象 |
EventTarget | 提供事件支持 |
Node | 提供parentNode 等节点操作方法 |
Element | 提供getElementsByTagName 、querySelector 等方法 |
HTMLElement | 所有元素的基础类,提供className 、nodeName 等方法 |
HTMLHeadingElement | Head标题元素类 |
以下以元素节点<main>
标签为例,它的最终原型对象为ElementTarget.proptrpy
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<main id="main">
<!-- 注释节点 --></main>
</body>
<script>
let main = document.getElementById("main");
console.log(main.__proto__);
console.log(main.__proto__.__proto__);
console.log(main.__proto__.__proto__.__proto__);
console.log(main.__proto__.__proto__.__proto__.__proto__);
console.log(main.__proto__.__proto__.__proto__.__proto__.__proto__);
</script>
</html>
document
document
是window
对象的属性,是由HTMLDocument
类实现的实例。
document
包含DocumentType
(唯一)或html
元素(唯一)或comment
等元素
document
的原型链中也包含Node
,所以可以使用有关节点操作的方法如nodeType/nodeName
等
HTML
下面将通过使用节点的nodeType
属性判断来获取所有的元素节点。
let html = [...document.childNodes].filter((node) => {
if (node.nodeType === 1) {
return node
}
})[0]
console.log(html)
系统提供了简单的方式来获取html
中的所有元素节点。
console.log(document.documentElement)
文档信息
系统为document
对象提供了一些属性,可以快速获取一些常用信息。
属性 | 说明 |
---|---|
title | 获取和设置当前HTML 文档标题 |
URL | 获取当前HTML 文档的url |
domain | 获取当前HTML 文档的面域名 |
referrer | 获取当前HTML 文档的来源地址 |
使用title
属性可或获取和设置当前HTML
文档标题。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 相当于会把这里改成 DOM LEARN-->
</head>
<body>
</body>
<script>
console.log(document.title); // Document
document.title = "DOM LEARN";
console.log(document.title);
</script>
</html>
使用URL
属性可获取当前HTML
文档的url
。
<script>
console.log(document.URL); // http://127.0.0.1:5500/1.html
</script>
使用domain
属性可获取当前HTML
文档的面域名。
<script>
console.log(document.domain); // 127.0.0.1
</script>
使用referrer
属性可获取当前HTML
文档的来源地址。
<script>
console.log(document.referrer);
</script>
节点属性
不同类型的节点拥有不同属性,下面是节点属性的说明与示例。
nodeType
每个节点都有nodeType
属性,返回节点类型的数值。
节点类型 | 类型代号 |
---|---|
元素节点 | 1 |
属性节点 | 2 |
文本节点 | 3 |
CDATA节点 | 4 |
实体引用名称节点 | 5 |
实体名称节点 | 6 |
处理指令节点 | 7 |
注释节点 | 8 |
文档节点 | 9 |
文档类型节点 | 10 |
文档片段节点 | 11 |
DTD声明节点 | 12 |
nodeType
属性基本使用
<script>
console.log(document.querySelector("h1").nodeType); // 1
</script>
使用对象原型进行检测
<script>
let h1 = document.querySelector("h1");
console.log(h1 instanceof Element); // true
</script>
nodeName
属性nodeName
用于获取节点的名称
获取值为大写形式
nodeType | nodeName |
---|---|
1 | 元素名称如DIV |
2 | 属性名称 |
3 | #text |
8 | #comment |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>hello,world</h1>
<h2 class="show">标题</h2>
<!-- 注释 -->
文本
</body>
<script>
let h1 = document.querySelector("h1");
let h2Attr = document.querySelector("h2").attributes[0];
let comment = document.body.childNodes[5];
let text = document.body.childNodes[6];
// 获取为大写形式
console.log(h1.nodeName); // H1
console.log(h2Attr.nodeName); // class
console.log(comment.nodeName); // #comment
console.log(text.nodeName); // #text
console.log(document.body.nodeName); // BODY
</script>
</html>
tagName
nodeName
可以获取不限于元素的节点名,tagName
仅能用于获取元素节点名称。
tagName
存在于Element
类的原型中元素上使用
tagName
与nodeName
无异获取值为大写形式
<script>
console.log(document.querySelector("h1").tagName); // H1
console.log(document.body.tagName); // BODY
</script>
nodeValue
使用nodeValue
属性或data
方法获取节点值,也可以使用节点的data
属性获取节点内容。
元素节点获取不到任何值,请注意如果想获取
<input>
标签中的value
不应该使用该属性
nodeType | nodeValue |
---|---|
1 | null |
2 | 属性值 |
3 | 文本内容 |
8 | 注释内容 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>hello,world</h1>
<h2 class="show">标题</h2>
<!-- 注释 -->
文本
</body>
<script>
let h1 = document.querySelector("h1");
let h2Attr = document.querySelector("h2").attributes[0];
let comment = document.body.childNodes[5];
let text = document.body.childNodes[6];
console.log(h1.nodeValue); // null 元素节点获取不到值
console.log(h2Attr.nodeValue); // show
console.log(comment.nodeValue); // 注释
console.log(text.nodeValue); // 文本
</script>
</html>
使用data
属性获取节点内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>hello,world</h1>
<h2 class="show">标题</h2>
<!-- 注释 -->
文本
</body>
<script>
let h1 = document.querySelector("h1");
let h2Attr = document.querySelector("h2").attributes[0];
let comment = document.body.childNodes[5];
let text = document.body.childNodes[6];
console.log(h1.childNodes[0].data); // hello,world
console.log(h2Attr.data); // undefined
console.log(comment.data); // 注释
console.log(text.data); // 文本
</script>
</html>
节点选择
系统提供了丰富的选择节点Node
的操作方法
快速获取
系统针对特定的元素节点提供了快速选择的方式
方法 | 说明 |
---|---|
document.documentElement | 文档节点即html标签节点 |
document.body | body标签节点 |
document.head | head标签节点 |
document.links | 超链接集合 |
document.anchors | 所有锚点集合 |
document.forms | form表单集合 |
document.images | 图片集合 |
返回
HTMLCollection
节点列表对象
下面以获取<a>
标签举例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<a href="#">a1</a>
<a href="#">a2</a>
<a href="#">a3</a>
</body>
<script>
let links = document.links;
console.log(links); // HTMLCollection(3) [a, a, a]
</script>
</html>
getElementById
使用id
进行元素节点是非常方便的选择,它会选择出所有具有id
属性的元素节点,但注意id
应该是唯一的
返回单一选中的元素节点
只能在
document
对象上使用此方法
以下示例将展示通过id
选择器选择出<main>
标签
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<main id="main_1">这是一个main标签</main>
</body>
<script>
let main = document.getElementById("main_1");
console.log(main); // <main id="main-1">这是一个main标签</main>
</script>
</html>
拥有标准属性id
的元素可做为window
对象的属性进行访问,但注意不要与变量名进行重合,所以不推荐这种方式。
这也是为什么推荐在为标签id
属性取名的时候用-
进行分割而不是用_
进行分割的原因。
<script>
console.log(main_1); // <main id="main_1">这是一个main标签</main>
</script>
getElementById
只能通过document
进行调用,不能通过元素读取拥有id
的子元素,下面的操作将产生错误。
这是因为该方法是存在于document
对象的原型中,而并不存在于任何节点元素的原型链上。
<script>
let main = document.getElementById("main_1");
main.getElementById("div-1");
// Uncaught TypeError: main.getElementById is not a function
</script>
getElementByName
使用getElementByName
获取设置了name
属性的元素,虽然在div
等元素上同样有效,但一般用来对表单元素进行操作时使用。
返回
NodeList
节点列表对象
NodeList
顺序为元素在文档中的顺序
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div name="username">这是普通的div哦</div>
<form action="#">
<input type="text" name="username" />
<input type="password" name="pwd" />
<button type="button" value="提交"></button>
</form>
</body>
<script>
let nameList = document.getElementsByName("username");
console.log(nameList); // NodeList(2) [div, input]
</script>
</html>
getElementsByTagName
使用getElementsByTagName
用于按标签名获取元素
返回
HTMLCollection
节点列表对象不区分大小的获取
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div name="username">这是普通的div哦</div>
<form action="#">
<input type="text" name="username" />
<input type="password" name="pwd" />
<button type="button" value="提交"></button>
</form>
</body>
<script>
let tagNameList = document.getElementsByTagName("input");
console.log(tagNameList); // HTMLCollection(2) [input, input, username: input, pwd: input]
</script>
</html>
通配符
可以使用通配符 *
获取所有元素
<script>
let tagList = document.getElementsByTagName("*");
console.log(tagList); // HTMLCollection(13) [html, head, meta, meta, title, body, div, form, input, input, button, script, script, viewport: meta, username: div, pwd: input]
</script>
某个元素也可以使用通配置符*
获取后代元素,下面获取 id
为main-1
的所有后代元素
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<main id="main-1">
<nav>导航</nav>
<header>头部</header>
<article>主题</article>
<footer>尾部</footer>
</main>
</body>
<script>
let main = document.getElementById("main-1");
let tagList = main.getElementsByTagName("*");
console.log(tagList); // HTMLCollection(4) [nav, header, article, footer]
</script>
</html>
getElementsByClassName
getElementsByClassName
用于按class
样式属性值获取元素集合
返回
HTMLCollection
节点列表对象设置多个值时顺序无关,只包含这些
class
属性的元素
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="show"></div>
<div class="show"></div>
<div class="show"></div>
</body>
<script>
let showClassList = document.getElementsByClassName("show");
console.log(showClassList); // HTMLCollection(3) [div.show, div.show, div.show]
</script>
</html>
样式选择器
在CSS
中可以通过样式选择器修饰元素样式,在DOM
操作中也可以使用这种方式查找元素。使用过jQuery
库的朋友,应该对这种选择方式印象深刻。
使用getElementsByTagName
等方式选择元素不够灵活,建议使用下面的样式选择器操作,更加方便灵活
querySelectorAll
使用querySelectorAll
根据CSS
选择器获取Nodelist
节点列表
返回
NodeList
节点列表对象该
NodeList
节点列表是静态的,添加或删除元素后不变
获取id
为main-1
下class
为show
的div
标签
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<main id="main-1">
<div>不是我</div>
<div class="show">是我</div>
<div class="show">是我</div>
<div>不是我</div>
<article class="show">不是我</article>
<article class="show">不是我</article>
</main>
</body>
<script>
let divList = document.querySelectorAll("#main-1 div.show")
console.log(divList); // NodeList(2) [div.show, div.show]
</script>
</html>
获取所有属性中含有bg
的div
标签
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div bg="red"></div>
<div></div>
<div bg="green"></div>
<article bg="#fff"></article>
<div></div>
</body>
<script>
let divList = document.querySelectorAll("div[bg]")
console.log(divList); // NodeList(2) [div, div]
</script>
</html>
querySelector
querySelector
使用CSS
选择器获取一个元素,下面是根据属性获取单个元素
返回单一选中的元素节点
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div bg="red"></div>
<div></div>
<div bg="green"></div>
<article bg="#fff"></article>
<div></div>
</body>
<script>
let divList = document.querySelector("div[bg]");
console.log(divList); // <div bg="red"></div>
</script>
</html>
matches
用于检测元素是否可以被指定的样式选择器所匹配。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div bg="red"></div>
<div></div>
<div bg="green"></div>
<article bg="#fff"></article>
<div></div>
</body>
<script>
let eleList = document.getElementsByTagName("*"); // 拿到所有元素节点
Array.prototype.forEach.call(eleList,((ele) => {
console.log(ele.matches("[bg]")); // 验证是否有属性bg
}));
// 6 false
// true
// false
// 2 true
// 3 false
</script>
</html>
closest
查找最近的符合选择器的祖先元素(包括自身)。
找祖先,看最近的祖先能不能被选择器选中,如果不能继续向上找。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<main class="show">
<div class="hidden">
<article class="float"></article>
</div>
</main>
</body>
<script>
let floatEle = document.querySelector(".float");
console.log(floatEle.closest(".show")); // 找到main标签
</script>
</html>
关系获取
节点关系
节点是根据HTML
内容产生的,所以也存在父子、兄弟、祖先、后代等节点关系。
注意:文本节点和注释节点也在节点关系之中
节点属性 | 说明 |
---|---|
childNodes | 获取所有子节点 |
parentNode | 获取父节点 |
firstChild | 子节点中第一个 |
lastChild | 子节点中最后一个 |
nextSibling | 下一个兄弟节点 |
previousSibling | 上一个兄弟节点 |
获取所有子节点(换行也包括其中)
<body>
<main>
文本
<div>div标签</div>
<article>article标签</article>
<!-- 注释 -->
</main>
</body>
<script>
let main = document.querySelector("main");
let mainChild = main.childNodes;
console.log(mainChild);
// NodeList(7) [text, div, text, article, text, comment, text]
</script>
获取父节点(文本节点不能作为父节点)
<body>
<main>
文本
<div>div标签</div>
<article>art<aside>找爸爸</aside>icle标签</article>
<!-- 注释 -->
</main>
</body>
<script>
let aside = document.querySelector("aside");
console.log(aside.parentNode);
/*
<article>
art<aside>找爸爸</aside>icle标签
</article>
*/
</script>
元素关系
使用childNodes
等获取的节点包括文本与注释,但这不是我们常用的,系统也提供了只操作元素的关系 方法。
节点属性 | 说明 |
---|---|
parentElement | 获取父元素 |
children | 获取所有子元素 |
childElementCount | 子标签元素的数量 |
firstElementChild | 第一个子标签 |
lastElementChild | 最后一个子标签 |
previousElementSibling | 上一个兄弟标签 |
nextElementSibling | 下一个兄弟标签 |
获取所有子元素
<body>
<main>
文本
<div>div标签</div>
<article>article标签</article>
<!-- 注释 -->
</main>
</body>
<script>
let main = document.querySelector("main");
let mainChildElement = main.children;
console.log(mainChildElement);
// HTMLCollection(2) [div, article]
</script>
获取父元素
<body>
<main>
文本
<div>div标签</div>
<article>art<aside>找爸爸</aside>icle标签</article>
<!-- 注释 -->
</main>
</body>
<script>
let aside = document.querySelector("aside");
console.log(aside.parentElement);
/*
<article>
art<aside>找爸爸</aside>icle标签
</article>
*/
</script>
节点集合
NodeList
与HTMLCollection
都是包含多个节点标签的集合,大部分功能也是相同的
getElementsBy...
等方法返回的是HTMLCollection
querySelectorAll
返回的是NodeList
NodeList
节点列表是动态的,即内容添加后会动态获取
<script>
let divList1 = document.querySelectorAll("div");
console.log(divList1); // NodeList(3) [div, div, div]
let divList2 = document.getElementsByTagName("div");
console.log(divList2); // HTMLCollection(3) [div, div, div]
</script>
length
NodeList
与HTMLCollection
包含length
属性,记录了节点元素的数量
<script>
let divList = document.querySelectorAll("div");
console.log(divList.length); // 3
</script>
转换数组
想要将nodeList
或者HTMLCollection
转换为Array
调用其下的方法可使用以下三种方式
1.不转换数组而使用
call()
方法进行方法借用2.使用
Array.from()
将其转换为Array
3.使用
...
将其转换为Array
以下示例将展示使用call()
方法进行方法借用
<script>
let divList = document.querySelectorAll("div"); // nodeList 不具有map方法。
Array.prototype.map.call(divList, (ele) => {
console.log(ele);
})
</script>
以下示例将展示使用Array.from()
将nodeList
转换为Array
<script>
let divList = document.querySelectorAll("div"); // nodeList 不具有map方法。
Array.from(divList).map((ele)=>{
console.log(ele);
})
</script>
以下示例将展示使用...
语法将nodeList
转换为Array
<script>
let divList = document.querySelectorAll("div"); // nodeList 不具有map方法。
[...divList].map((ele)=>{
console.log(ele);
})
</script>
item
Nodelist
与HTMLCollection
提供了item()
方法来根据索引获取元素
<script>
let divList = document.querySelectorAll("div");
console.log(divList.item(0));
// 效果相同
console.log(divList[0]);
</script>
namedItem
HTMLCollection
具有namedItem
方法可以按name
或id
属性来获取元素
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div name="d1">1</div>
<div id="d2">2</div>
<div>3</div>
</body>
<script>
let divList = document.getElementsByTagName("div"); // 必须是HTMLcollection类型才行。nodeList不支持
console.log(divList.namedItem("d1")); // <div name="d1">1</div>
console.log(divList.namedItem("d2")); // <div id="d2">2</div>
</script>
</html>
也可以使用数组或属性的方式来取
<script>
let divList = document.getElementsByTagName("div");
console.log(divList["d1"]); // <div name="d1">1</div>
console.log(divList.d2); // <div id="d2">2</div>
</script>
动态与静态
使用NodeList
获取的标签集合如果页面中新增了一个同类型标签会进行动态映射。
而HTMLCollection
标签集合则没有这种特性。
注意:
querySelectAll
的NodeList
是静态的。
动态特性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div name="show">div1</div>
<div name="show">div2</div>
<div name="show">div3</div>
</body>
<script>
let divList = document.getElementsByName("show");
console.log(divList.length); // 3
let newDiv = document.createElement("div"); // 创建标签
newDiv.innerText = "div4"; // 设置文本内容
newDiv.setAttribute("name","show"); // 设置属性
document.body.append(newDiv);
console.log(divList.length); // 4
</script>
</html>
querySelectAll
的NodeList
是静态的。
<body>
<div name="show">div1</div>
<div name="show">div2</div>
<div name="show">div3</div>
</body>
<script>
let divList = document.querySelectorAll("[name=show]");
console.log(divList.length); // 3
let newDiv = document.createElement("div"); // 创建标签
newDiv.innerText = "div4"; // 设置文本内容
newDiv.setAttribute("name","show"); // 设置属性
document.body.append(newDiv); // 新增的div4并没有被动态映射
console.log(divList.length); // 3
</script>
集合遍历
尽管可以使用for/in
进行遍历,但是并不推荐使用它。
因为它会将该集合中可调用的属性遍历出来,而不仅仅是只遍历出元素本身。
for
节点集合对象不论是NodeList
还是HTMLCollection
对象都具有length
属性,因此可以对其进行遍历操作。
<body>
<div class="show"></div>
<div class="show"></div>
<div class="show"></div>
</body>
<script>
let showClassList = document.getElementsByClassName("show");
for (let i = 0; i < showClassList.length; i++) {
console.log(showClassList[i]); // 只取出元素
}
</script>
for/of
节点的集合对象均可使用for/of
进行遍历操作。
<body>
<div class="show"></div>
<div class="show"></div>
<div class="show"></div>
</body>
<script>
let showClassList = document.getElementsByClassName("show");
for (let ele of showClassList) {
console.log(ele); // 只取出元素
}
</script>
forEach
NodeList
节点列表也可以使用forEach
来进行遍历,但HTMLCollection
则不可以。
<body>
<div class="show"></div>
<div class="show"></div>
<div class="show"></div>
</body>
<script>
let showClassList = document.querySelectorAll(".show");
showClassList.forEach((ele, index) => { // 第三个参数为遍历的对象本身
console.log(ele); // 元素本身
console.log(index); // index索引
})
</script>
map
虽然NodeList
与HTMLCollection
本身并不提供map
方法进行遍历,但是我们可以通过方法借用或数组转换实现。
<body>
<div class="show"></div>
<div class="show"></div>
<div class="show"></div>
</body>
<script>
let showClassList = document.querySelectorAll(".show");
Array.prototype.map.call(showClassList,(ele, index,list) => { // 第三个参数为遍历的对象本身
console.log(ele); // 元素本身
console.log(index); // index索引
})
</script>
Array.from
Array.from
用于将类数组转为组件,并提供第二个迭代函数。所以可以借用Array.from
实现遍历
<body>
<div class="show"></div>
<div class="show"></div>
<div class="show"></div>
</body>
<script>
let showClassList = document.querySelectorAll(".show");
Array.from(showClassList,(ele, index) => {
console.log(ele); // 元素本身
console.log(index); // index索引
})
</script>
创建节点
createTextNode
创建一个文本对象
<body>
<div></div>
</body>
<script>
let text = document.createTextNode("这是一个div");
let div = document.querySelector("div");
div.append(text);
</script>
createElement
创建一个标签对象
<script>
let div = document.createElement("div");
div.style.width = "50px";
div.style.height = "50px";
div.style.background = "red";
document.body.append(div);
</script>
使用Promise
结合节点操作来加载外部JavaScript
文件
function js(file) {
return new Promise((resolve, reject) => {
let js = document.createElement('script')
js.type = 'text/javascript'
js.src = file
js.onload = resolve
js.onerror = reject
document.head.appendChild(js)
})
}
js('1.js')
.then(() => console.log('加载成功'))
.catch((error) => console.log(`${error.target.src} 加载失败`))
使用同样的逻辑来实现加载CSS
文件
function css(file) {
return new Promise((resolve, reject) => {
let css = document.createElement('link')
css.rel = 'stylesheet'
css.href = file
css.onload = resolve
css.onerror = reject
document.head.appendChild(css)
})
}
css('1.css').then(() => {
console.log('加载成功')
})
createDocumentFragment
使用createDocumentFragment
创建虚拟的节点容器
创建的节点的
parentNode
为null
使用
createDocumentFragment
创建的节点来暂存文档节点
createDocumentFragment
创建的节点添加到其他节点上时,会将子节点一并添加
createDocumentFragment
是虚拟节点对象,不直接操作DOM
所以性能更好在排序/移动等大量DOM操作时建议使用
createDocumentFragment
如果将该容器节点添加到页面中,将不会进行显示
cloneNode&importNode
使用cloneNode
和document.importNode
用于复制节点对象操作
cloneNode
是节点方法
cloneNode
参数为true
时递归复制子节点即深拷贝
importNode
是documet
对象方法
使用cloneNode
克隆节点且参数为true
时会将原标签的事件等也一同进行拷贝。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div onclick="show(this,event)" style="width: 100px;height: 100px;background: red;" ></div>
</body>
<script>
function show(ele,event) {
ele.style.backgroundColor="blue";
}
let div = document.querySelector("div");
document.body.append(div.cloneNode(true));
</script>
</html>
document.importNode
方法是部分IE浏览器不支持的,也是复制节点对象的方法
第一个参数为节点对象
第二个参数为
true
时递归复制
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div onclick="show(this,event)" style="width: 100px;height: 100px;background: red;" ></div>
</body>
<script>
function show(ele,event) {
ele.style.backgroundColor="blue";
}
let div = document.querySelector("div");
document.body.append(document.importNode(div,true));
</script>
</html>
节点内容
innerHTML
inneHTML
用于获取标签中的HTML
内容,并且也可以向标签中添加HTML
内容,同时触发浏览器的解析器重绘DOM。
下例使用innerHTML
获取和设置<div>
内容
innerHTML
中只解析HTML
标签语法,所以其中的<script>
不会做为Js
处理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div></div>
</body>
<script>
let div = document.querySelector("div");
div.innerHTML = "<h1>欢迎学习JavaScript的DOM操作</h1>"
</script>
</html>
outerHTML
outerHTML
与innerHTML
的区别是包含父标签
outerHTML
不会删除原来的旧元素只是用新内容替换替换旧内容,旧内容(元素)依然存在
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div><p>旧内容</p></div>
</body>
<script>
let div = document.querySelector("div");
console.log(div.outerHTML); // <div><p>旧内容</p></div>
console.log(div.innerHTML); // 不包含自身 <p>旧内容</p>
div.outerHTML = "<p>欢迎学习JavaScript的DOM操作</p>" // 将div替换成p
</script>
</html>
innerHTML&textContent
textContent
与innerText
是访问或添加文本内容到元素中
textContentb
部分IE浏览器版本不支持
innerText
部分FireFox
浏览器版本不支持获取时忽略所有标签
设置时将内容中的标签当文本对待不进行解析
获取时忽略内容中的所有标签
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div><article>外层文本<time>内层文本</time></article></div>
</body>
<script>
let div = document.querySelector("div");
console.log(div.innerText); // 外层文本内层文本
console.log(div.textContent); // 外层文本内层文本
</script>
</html>
设置时将标签当文本对待,即转为HTML
实体内容
<script>
let div = document.querySelector("div");
div.innerText = "<p>不会解析成标签</p>";
</script>
outerText
与innerText
差别是会影响所操作的标签,即将标签替换为纯文本。
<script>
let div = document.querySelector("div");
div.outerText = "<p>不会解析成标签</p>";
</script>
节点管理
包括添加、删除、替换等操作
推荐方法
方法 | 说明 |
---|---|
append | 节点内部的尾部追加新节点或字符串 |
prepend | 节点内部的头始插入新节点或字符串 |
before | 节点同级的前面插入新节点或字符串 |
after | 节点同级的后面追加新节点或字符串 |
replaceWith | 将节点替换为新节点或字符串 |
节点内部的尾部追加新节点或字符串
<body>
<div><p>原本内容</p></div>
</body>
<script>
let div = document.querySelector("div");
let article = document.createElement("article");
article.innerText = "新内容";
div.append(article);
/*
<div>
<p>原本内容</p>
<article>新内容</article>
</div>
*/
</script>
节点内部的头始插入新节点或字符串
<body>
<div><p>原本内容</p></div>
</body>
<script>
let div = document.querySelector("div");
let article = document.createElement("article");
article.innerText = "新内容";
div.prepend(article);
/*
<div>
<article>新内容</article>
<p>原本内容</p>
</div>
*/
</script>
节点同级的前面插入新节点或字符串
<body>
<div><p>原本内容</p></div>
</body>
<script>
let div = document.querySelector("div");
let article = document.createElement("article");
article.innerText = "新内容";
div.before(article);
/*
<article>新内容</article>
<div>
<p>原本内容</p>
</div>
*/
</script>
节点同级的后面追加新节点或字符串
<body>
<div><p>原本内容</p></div>
</body>
<script>
let div = document.querySelector("div");
let article = document.createElement("article");
article.innerText = "新内容";
div.after(article);
/*
<div>
<p>原本内容</p>
</div>
<article>新内容</article>
*/
</script>
将节点替换为新节点或字符串
<body>
<div><p>原本内容</p></div>
</body>
<script>
let div = document.querySelector("div");
let article = document.createElement("article");
article.innerText = "新内容";
div.replaceWith(article);
/*
<article>新内容</article>
*/
</script>
insertAdjacentText
将文本插入到元素指定位置,不会对文本中的标签进行解析,包括以下位置
选项 | 说明 |
---|---|
beforebegin | 元素本身前面 |
afterend | 元素本身后面 |
afterbegin | 元素内部前面 |
beforeend | 元素内部后面 |
将文本内容添加到元素本身前面
<body>
<div><p>原本内容</p></div>
</body>
<script>
let div = document.querySelector("div");
div.insertAdjacentText("beforebegin","<p>新内容</p>"); // 不会解析成标签
/*
<p>新内容</p>
<div>
<p>原本内容</p>
</div>
*/
</script>
insertAdjacentHTML
将HTML
文本插入到元素指定位置,浏览器会对文本进行标签解析,包括以下位置
选项 | 说明 |
---|---|
beforebegin | 元素本身前面 |
afterend | 元素本身后面 |
afterbegin | 元素内部前面 |
beforeend | 元素内部后面 |
将HTML
文本添加到元素本身前面
<body>
<div><p>原本内容</p></div>
</body>
<script>
let div = document.querySelector("div");
div.insertAdjacentHTML("beforebegin","<p>新内容</p>"); // 会解析成标签
/*
<p>新内容</p>
<div>
<p>原本内容</p>
</div>
*/
</script>
insertAdjacentElement
insertAdjacentElement()
方法将指定元素插入到元素的指定位置,包括以下位置
选项 | 说明 |
---|---|
beforebegin | 元素本身前面 |
afterend | 元素本身后面 |
afterbegin | 元素内部前面 |
beforeend | 元素内部后面 |
将<article>
标签添加到元素本身前面
<body>
<div><p>原本内容</p></div>
</body>
<script>
let div = document.querySelector("div");
let article = document.createElement("article");
article.innerText = "新内容";
div.insertAdjacentElement("beforebegin",article);
/*
<article>新内容</article>
<div>
<p>原本内容</p>
</div>
*/
</script>
古老方法
下面是过去使用的操作节点的方法,现在不建议使用了。但在阅读老代码时可来此查看语法
方法 | 说明 |
---|---|
appendChild | 添加节点 |
insertBefore | 用于插入元素到另一个元素的前面 |
removeChild | 删除节点 |
replaceChild | 进行节点的替换操作 |
标准属性
元素的标准属性具有相对应的DOM
对象属性
操作属性区分大小写
多个单词属性命名规则为第一个单词小写,其他单词大写
属性值是多类型并不全是字符串
事件处理程序属性值为函数
style
属性为CSSStyleDeclaration
对象
DOM
对象不同生成的属性也不同
属性别名
有些属性名与Js
关键词冲突,系统已经起了别名
属性 | 别名 |
---|---|
class | className |
for | htmlFor |
操纵属性
元素的标准属性可以直接进行操作,下面是直接设置元素的className
<body>
<main></main>
</body>
<script>
let main = document.querySelector("main");
main.className = "show";
</script>
下面设置图像元素的标准属性
<body>
<img src="" alt="" />
</body>
<script>
let img = document.img[0];
img.src = "./1.png";
img.alt = "没加载出来...";
</script>
使用hidden
隐藏元素
<body>
<main>main标签</main>
</body>
<script>
document.querySelector("main").addEventListener("click", (ele) => {
ele.target.hidden = true;
});
</script>
多类型
大部分属性值是都是字符串,但并不是全部。
比如checked
的值就是Boolean
类型
<body>
<input type="checkbox" name="gender" value="male" checked />
<input type="checkbox" name="gender" value="female" />
</body>
<script>
let input = document.getElementsByName("gender").item(0).addEventListener("change", (event) => {
console.log(event.target.checked); // 修改事件绑定 查看checked
})
</script>
属性值并不都与HTML
中的内容相同,下列<a>
标签的href
属性获取出的就是完整链接
<script>
let tagA = document.querySelector("a");
console.log(tagA.href); // http://127.0.0.1:5500/test
</script>
特征属性
特征属性是指自定义的元素属性,对于标准的属性可以使用DOM
属性的方式进行操作,但对于标签的非标准的自定义属性则不可以。但Js
提供了相应的操作非标准属性的方式来控制标准或非标准的属性。
可以理解为元素的属性分两个地方保存,DOM
属性中记录标准属性,特征中记录标准和定制属性
使用特征操作时属性名称不区分大小写
特征值都为字符串类型
推荐方法
使用以下方法可以操纵特征属性与标准属性。
方法 | 说明 |
---|---|
getAttribute | 获取属性 |
setAttribute | 设置属性 |
removeAttribute | 删除属性 |
hasAttribute | 检测某一属性是否存在 |
使用getAttribute
来获取某一元素的特征属性或标准属性。
<body>
<article content="内容块" color="#fff" class="show">HELLO,WORLD</article>
</body>
<script>
let eleTag = document.querySelector("[color]");
console.log(eleTag.getAttribute("content")); // 支持获取特征属性
console.log(eleTag.getAttribute("class")); // 支持获取标准属性
</script>
使用setAttribute
来设置某一元素的特征属性或标准属性。
<body>
<article content="内容块" color="#fff" class="show">HELLO,WORLD</article>
</body>
<script>
let eleTag = document.querySelector("[color]");
eleTag.setAttribute("content","内容区域"); // 支持设置特征属性
eleTag.setAttribute("class","hidden"); // 支持设置标准属性
</script>
使用removeAttribute
来删除某一元素的特征属性或标准属性。
<body>
<article content="内容块" color="#fff" class="show">HELLO,WORLD</article>
</body>
<script>
let eleTag = document.querySelector("[color]");
eleTag.removeAttribute("content"); // 支持删除特征属性
eleTag.removeAttribute("class"); // 支持删除标准属性
</script>
使用hasAttribute
来检测某一元素的特征属性或标准属性是否存在。
<body>
<article content="内容块" color="#fff" class="show">HELLO,WORLD</article>
</body>
<script>
let eleTag = document.querySelector("[color]");
console.log(eleTag.hasAttribute("content")); // 支持检测特征属性
console.log(eleTag.hasAttribute("class")); // 支持检测标准属性
</script>
获取到的属性值均为string
类型
<body>
<input type="text" name="age" value="18">
</body>
<script>
let eleTag = document.querySelector("[name=age]");
console.log(typeof eleTag.value); // string
</script>
attributes
元素提供了attributes
属性可以只读的获取元素的属性
<body>
<article content="内容块" color="#fff" class="show">HELLO,WORLD</article>
</body>
<script>
let eleTag = document.querySelector("[color]");
console.log(eleTag.attributes['content'].nodeValue); // 内容块
console.log(eleTag.attributes['class'].nodeValue); // show
</script>
attributes
属性会返回一个NamedNodeMap
的可迭代对象,因此可以对他进行迭代取值的操作。
<body>
<article content="内容块" color="#fff" class="show">HELLO,WORLD</article>
</body>
<script>
let eleTag = document.querySelector("[color]");
for (let attr of eleTag.attributes){
console.log(attr);
}
/*
content="内容块"
color="#fff"
class="show"
*/
</script>
属性集
如果单纯的对特征属性进行任意命名,可能会和标准属性产生冲突。
因此可以使用前缀的方式进行特征属性的命名,如data-xxx
,针对这种定义方式Js
也提供了接口方便操作
元素中以
data-
为前缀的属性会添加到属性集中使用元素的
dataset
可获取属性集中的属性改变
dataset
的值也会影响到元素上
使用dataset
属性集
<body>
<article data-content="内容块" data-color="#fff" class="show">HELLO,WORLD</article>
</body>
<script>
let eleTag = document.querySelector("article");
console.log(eleTag.dataset.content); // 内容块
</script>
以-
命名的特征属性,在使用属性集获取时要采用驼峰式命名法获取。
<body>
<article data-content-top-left="顶部左区域内容块" data-color="#fff" class="show">HELLO,WORLD</article>
</body>
<script>
let eleTag = document.querySelector("article");
console.log(eleTag.dataset.contentTopLeft); // 顶部左区域内容块
</script>
改变dataset
值也会影响到页面元素上
<body>
<article data-content-top-left="顶部左区域内容块" data-color="#fff" class="show">HELLO,WORLD</article>
</body>
<script>
let eleTag = document.querySelector("article");
eleTag.dataset.contentTopLeft = "左区域顶部内容块";
</script>
表单控制
表单查找
Js
为表单的操作提供了单独的集合控制
使用
document.forms
获取表单集合使用
form
的name
属性获取指定form
元素根据表单项的
name
属性使用form.elements.title
获取表单项,也可以直接写成
form.name
形式,不需要form.elements.title
针对
radio/checkbox
获取的表单项是一个集合
使用document.forms
与form.elements
<body>
<form action="#" name="register">
<input type="text" name="username">
<input type="text" name="pwd">
</form>
</body>
<script>
let form = document.forms.register; // 获取到表单
let formChildren = form.elements; // 拿到其下所有表单项
let username = form.elements.username; // 拿到name为username的表单项
console.log(formChildren); // HTMLFormControlsCollection(2) [input, input, username: input, pwd: input]
console.log(username); // <input type="text" name="username">
</script>
样式管理
通过DOM
修改样式可以通过更改元素的class
属性或通过style
对象设置行样式来完成。
建议使用
class
控制样式,将任务交给CSS
处理,更简单高效
classList
如果对类单独进行控制使用 classList
属性操作
方法 | 说明 |
---|---|
node.classList.add | 添加类名 |
node.classList.remove | 删除类名 |
node.classList.toggle | 切换类名 |
node.classList.contains | 检测元素类名是否存在 |
在元素的原有class
上添加新class
<body>
<section class="show left"></section>
</body>
<script>
let section = document.querySelector("section");
section.classList.add("top");
</script>
移除原本元素的某个class
<body>
<section class="show left"></section>
</body>
<script>
let section = document.querySelector("section");
section.classList.remove("show");
// <section class="left"></section>
</script>
将原本元素的某个class
切换为另一个class
,即类已经存在时删除,不存在时添加
<body>
<section class="show left"></section>
</body>
<script>
let section = document.querySelector("section");
section.classList.toggle("show"); // 存在删除
section.classList.toggle("hidden"); // 不存在添加
// <section class="left hidden"></section>
</script>
使用contains
检查class
是否存在
<body>
<section class="show left"></section>
</body>
<script>
let section = document.querySelector("section");
let result = section.classList.contains("show");
console.log(result); // true
</script>
style&cssText
使用style
可以单独的为某一个元素进行单独的样式设置
多个单词的属性使用驼峰进行命名,不要使用
-
进行分割
<body>
<section>文字</section>
</body>
<script>
let section = document.querySelector("section");
section.style.color = "blue";
section.style.backgroundColor = "red"; // background-color 需要改成驼峰体设置 backgroundColor
</script>
使用cssText
属性可以批量设置行样式,属性名和写CSS
一样不需要考虑驼峰命名
<body>
<section>文字</section>
</body>
<script>
let section = document.querySelector("section");
section.style.cssText = "color:blue;background-color:red;"
</script>
也可以使用setAttribute
批量进行样式设置,属性名和写CSS
一样不需要考虑驼峰命名
<body>
<section>文字</section>
</body>
<script>
let section = document.querySelector("section");
section.setAttribute("style","color:blue;background-color:red;")
</script>
获取样式
可以通过style
对象,window.window.getComputedStyle
对象获取样式属性,下面进行说明
可以使用DOM
对象的style
属性读取行样式
style
对象不能获取行样式外定义的样式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
section{
color: blue;
}
</style>
</head>
<body>
<section style="background-color: red;">文字</section>
</body>
<script>
let section = document.querySelector("section");
console.log(section.style.backgroundColor); // red
console.log(section.style.color); // 空白,获取不到
</script>
</html>
使用window.getComputedStyle
可获取所有应用在元素上的样式属性
函数第一个参数为元素
第二个参数为伪类
这是计算后的样式属性,所以取得的单位和定义时的可能会有不同
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
section{
color: blue;
font-size: 18px;
}
</style>
</head>
<body>
<section style="background-color: red;">文字</section>
</body>
<script>
let section = document.querySelector("section");
let bgColor = window.getComputedStyle(section).backgroundColor;
console.log(bgColor); // rgb(255, 0, 0)
let fontColor = window.getComputedStyle(section).color;
console.log(fontColor); // rgb(0, 0, 255)
let fontSize = window.getComputedStyle(section).fontSize;
console.log(fontSize); // 18px
</script>
</html>