JavaScript DOM 基础知识 document 节点属性 节点选择 样式选择器 关系获取 节点集合 集合遍历 创建节点 节点内容 节点管理 标准属性 特征属性 表单控制 样式管理
在书写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 >
<!-- 注释节点 --></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 >
<!-- 注释节点 --></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 >这是一个main标签</main>
</body>
<script>
let main = document.getElementById("main_1");
console.log(main); // <main >这是一个main标签</main>
</script>
</html>
拥有标准属性id
的元素可做为window
对象的属性进行访问,但注意不要与变量名进行重合,所以不推荐这种方式。
这也是为什么推荐在为标签id
属性取名的时候用-
进行分割而不是用_
进行分割的原因。
<script>
console.log(main_1); // <main >这是一个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 >
<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 >
<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 >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 >2</div>
</script>
</html>
也可以使用数组或属性的方式来取
<script>
let divList = document.getElementsByTagName("div");
console.log(divList["d1"]); // <div name="d1">1</div>
console.log(divList.d2); // <div >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=" 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=" 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>