在前面的JS基础阶段中,我们学习的是ECMAScript标准规定的基本语法,但是只学习基本语法是无法做出网页交互效果的,为此在本章的学习中,我们要进入WebAPIs阶段。
WebAPIs是W3C组织的标准,主要学习DOM和BOM,在这一章节中,我们需要JS基本语法的铺垫,步入学习网页交互功能的道路。
当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model),它是W3C组织推荐的处理可扩展标记语言的标准编程接口,其结构为一颗DOM对象树。如果学过Python爬虫中的Xpath解析框架,你可以很好的理解我上述的话。

Js可以通过DOM对HTML文档进行操作,即随心所欲操作Web界面。
节点Node是构建网页最基本的组成部分。网页中的每一个部分都可看做是一个节点。节点类型多样,属性和方法也不尽相同,最常用的节点可以分为以下四类:
对于每个节点来说都具备nodeName、nodeType、nodeValue三个属性。
| nodeName | nodeType | nodeValue | |
|---|---|---|---|
| 文档节点 | #document | 9 | Null |
| 元素节点 | 标签名 | 1 | Null |
| 属性节点 | 属性名 | 2 | 属性值 |
| 文本节点 | #text | 3 | 文本内容 |
浏览器为我们提供了文档节点对象document,这个对象是window属性。如果你希望访问HTML页面中的任何元素,那么你必须从访问document对象开始。
文档节点对象可以在页面中直接使用,文档节点代表的是整个网页
| 方法 | 说明 |
|---|---|
| document.getElementById(‘id’) | 元素id查找元素 |
| document.getElementByTagName(‘name’) | 标签名查找元素 |
| document.getElementByClassName(‘name’) | 类名查找元素 |
| document.querySelector(‘CSS选择器’) | 根据CSS选择器返回第一个元素 |
| document.querySelectorAll(‘CSS选择器’) | 通过CSS选择器选择多个元素 |
| document.body | 选择body标签的所有内容 |
| document.documentElement | 选择html标签的所有内容 |
注:JS是解释性语言,故JS代码必须写在HTML的下方,因为只有HTML生成元素了,JS才能通过DOM操纵元素。
DOCTYPE html>
<html lang="zh-cn">
<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>Documenttitle>
head>
<body>
<div id = "test">测试案例1div>
<p>测试案例2p>
<p>测试案例3p>
<div class="c1">测试案例4div>
<div class = "c2">测试案例5div>
<div id = "c3">测试案例6div>
<div id = "c3">测试案例7div>
<script>
//1 通过ID找元素,注意ID大小写敏感,返回值为
var test1 = document.getElementById('test');
console.log(test1);
console.dir(test1);//等同于log,用于查看元素结构
//2 通过标签名找元素,这种方式选中所有同名标签,返回值为伪数组
var test2 = document.getElementsByTagName('p');
console.log(test2);
//3 通过类名找元素,该方法仅支持IE9以上,返回值为伪数组
var test3 = document.getElementsByClassName('c1');
console.log(test3);
//4 通过选择器查找第一个元素
var test4 = document.querySelector('.c2');
console.log(test4);
//5 通过选择器选定所有元素
var test5 = document.querySelectorAll('#c3');
console.log(test5);
var test6 = document.querySelectorAll('*');
console.log(test6);
//6 得到body元素
var test7 = document.body;
console.log(test7);
//7 得到html元素
var test8 = document.documentElement;
console.log(test8);
script>
body>
html>
注:推荐学完事件再回来看
| 方法 | 说明 |
|---|---|
| 元素节点.innerText | 获取HTML元素标签间的内容 |
| 元素节点.innerHTML | 获取HTML元素标签间内容以及标签 |
| 元素节点.属性 | 获取HTML元素的属性值 |
| 元素节点.style.样式 | 获取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>Documenttitle>
<style>
#Test5 p{
height:50px;
width:100px;
background: pink;
}
style>
head>
<body>
<button>测试按钮1button>
<div>测试内容1div>
<br>
<div>
<button id = "testbtn2">测试按钮2button>
<p id = "test2">测试内容2p>
div>
<br>
<div>
<button id = "testbtn3">测试按钮3——图片1button>
<button id = "testbtn4">测试按钮4——图片2button>
<br>
<img src = "./img_103.jpg" alt = "" id = "testimg" width = 300px>
div>
<div id = "Test5">
<p>测试内容5p>
<br>
<button>测试按钮5button>
div>
<script>
/*======innerText======*/
//1 获取事件源
var btn1 = document.querySelector('button');
var div1 = document.querySelector('div');
//2 注册事件
btn1.onclick = function(){
div1.innerText = '测试内容已改变';
}
/*======innerHTML======*/
//1 获取事件源
var btn2 = document.getElementById('testbtn2')
var p2 = document.getElementById('test2');
//2 注册事件
btn2.onclick = function(){
p2.innerHTML = '测试内容已改变';
}
/*======元素节点.属性======*/
//1 获取事件源
var btn3 = document.getElementById('testbtn3');
var btn4 = document.getElementById('testbtn4');
var img3 = document.getElementById('testimg');
//2 注册事件
btn3.onclick = function(){
img3.src = './img_103.jpg';
}
btn4.onclick = function(){
img3.src = './img_112.jpg';
}
/*======元素节点.style.样式======*/
//1 获取事件源
var btn5 = document.querySelector('#Test5 button');
var p5 = document.querySelector('#Test5 p');
//2 注册事件
btn5.onclick = function(){
p5.style.background = 'skyblue';
}
script>
body>
html>
说明:如果要想通过DOM修改CSS样式,一个样式就要一条语句,十分难受。为此,我们可以将修改后的样式放在一个选择器中,当我们需要很多组件同时变成该样式时,使用元素.className修改该元素的所属的类,这样就可以给该元素附上提前准备好的样式。
注:className方法并不是添加类,而是覆盖类。这就意味着如果元素此前拥有的类将会被覆盖。
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>Documenttitle>
<style>
/*提前准备一个样式*/
.Test1{
color: yellowgreen;
background: pink;
}
style>
head>
<body>
<div>测试内容1div>
<button>测试按钮1button>
<script>
var div1 = document.querySelector('div');
var btn1 = document.querySelector('button');
btn1.onclick = function(){
div1.className = 'Test1';
}
script>
body>
html>
说明:之前的className容易覆盖以前的类名,故我们可以使用classList方式来追加和删除类名。
| 方式 | 说明 |
|---|---|
| 元素.classList.add(‘类名’) | 追加一个类 |
| 元素.classList.remove(‘类名’) | 删除一个类 |
| 元素.classList.toggle(‘类名’) | 切换一个类 |
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>Documenttitle>
<style>
/*提前准备一个样式*/
.Test1{
color: yellowgreen;
background: pink;
}
/*样式2*/
.Test2{
background-color: aqua;
}
style>
head>
<body>
<div class = "Test1">测试内容1div>
<button class = "add-btn">追加样式类button>
<button class = "remove-btn">删除样式类button>
<button class = "toggle-btn">切换样式类button>
<script>
var div = document.querySelector('div')
var add_btn = document.querySelector('.add-btn')
var remove_btn = document.querySelector('.remove-btn')
var toggle_btn = document.querySelector('.toggle-btn')
console.log(add_btn);
console.log(remove_btn);
add_btn.onclick = function(){
div.classList.add('Test2')
}
remove_btn.onclick = function(){
div.classList.remove('Test2');
}
toggle_btn.onclick = function(){
div.classList.toggle('Test1');
}
script>
body>
html>
说明:我们可以通过以下方法修改元素的内容
| 方法 | 说明 |
|---|---|
| 元素节点.innerText =新内容 | 改变元素的标签值 |
| 元素节点.innerHTML = 新元素 | 改变元素 |
| 元素节点.属性 = 新的属性值 | 改变元素的属性值 |
| 元素节点.setAttribute(属性, 值) | 改变元素的属性值 |
| 元素节点.style.样式 = 新的属性值 | 改变 HTML 元素的行内样式值 |
创建 HTML 元素节点:document.createElement(element)
创建 HTML 属性节点:document.createAttribute(attribute)
创建 HTML 文本节点:document.createTextNode(text)
删除 HTML 元素:元素节点.removeChild(element)
添加 HTML 元素:元素节点.appendChild(element)
替换 HTML 元素:元素节点.replaceChild(element)
在指定的子节点前面插入新的子节点:元素节点.insertBefore(element)
说明:offset指偏移量,我们使用offset系列相关属性可以动态地获取该元素的位置、大小等。需要注意的是,获取的仅有数值而无单位。
| 方法 | 说明 |
|---|---|
| 元素.offsetWidth | 返回自身包括padding、边框、内容区的宽度,返回数值不带单位 |
| 元素.offsetHeight | 返回自身包括padding、边框、内容区的高度,返回数值不带单位 |
| 元素.offsetParent | 获取离当前元素最近的开启了定位的祖先元素 |
| 元素.offsetTop | 返回元素相对带有定位父元素上方的偏移 |
| 元素.offsetLeft | 返回元素相对带有定位父元素左边框的偏移 |
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>Documenttitle>
<style>
*{
margin:0;
padding:0;
}
.div{
background-color: pink;
height: 200px;
width: 200px;
border: 2px solid red;
padding:2px;
}
style>
head>
<body>
<div class = "div">div>
<script>
var div = document.querySelector(".div")
// offsetWidth返回自身包括padding、边框、内容区的宽度,返回数值不带单位
console.log(div.offsetWidth);
// offsetHeight返回自身包括padding、边框、内容区的高度,返回数值不带单位
console.log(div.offsetHeight);
// offsetParent获取离当前元素最近的开启了定位的祖先元素
console.log(div.offsetParent);
// offsetTop返回元素相对带有定位父元素上方的偏移
console.log(div.offsetTop);
// offsetLeft返回元素相对带有定位父元素左边框的偏移
console.log(div.offsetLeft);
script>
body>
html>
| offset | style |
|---|---|
| offset可以得到任意样式表中的样式值 | style只能得到行内样式表中的样式值 |
| offset系列获得的数值是不带单位的 | style.width获得的是带有单位的字符串 |
| offsetWidth包含padding+border+width | style.width获得不包含padding和border的值 |
| offsetWidth等属性属于只读属性 | style.widh是可读写属性,可以获取也可以赋值 |
| 方法 | 说明 |
|---|---|
| 元素.clientWidth | 返回自身包括padding、内容区宽度、不含边框,返回数值不带单位 |
| 元素.clientHeight | 返回自身包括padding、内容区高度、不含边框,返回数值不带单位 |
| 元素.clientTop | 返回元素上边框的大小 |
| 元素.cllientLeft | 返回元素左边框的大小 |
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>Documenttitle>
<style>
div{
width: 200px;
height: 200px;
background-color: pink;
border: 3px solid skyblue;
margin: 0 auto;
}
style>
head>
<body>
<div>div>
<script>
var div = document.querySelector('div');
console.log(div.clientWidth); //200,说明不包含边框
console.log(div.clientHeight);//200 说明不包含边框
console.log(div.clientLeft);//3 边框的左边宽度为3
console.log(div.clientTop);//3 边框的顶部宽度为3
script>
body>
html>
| 方法 | 说明 |
|---|---|
| 元素.scrollTop | 返回被卷去的上侧距离,返回数值不带单位 |
| 元素.scrollLeft | 返回被卷去的左侧距离,返回数值不带单位 |
| 元素.scrollWidth | 返回自身实际的宽度,不含边框,返回数值不带单位 |
| 元素.scrollHeight | 返回自身实际的高度,不含边框,返回数值不带单位 |

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>Documenttitle>
<style>
div{
width:50px;
height:100px;
background-color: pink;
overflow: scroll;
border: 3px solid red;
}
style>
head>
<body>
<div>测试内容1 测试内容1 测试内容1 测试内容1 div>
<script>
var div = document.querySelector('div');
console.log(div.scrollHeight);//208 表名内容+padding的宽度为208
console.log(div.scrollTop); //0 表明没有内容在滚动条上面
console.log(div.scrollWidth);//33 表名内容+padding的宽度为33
console.log(div.scrollLeft);//0表名没有内容在滚动条左侧
script>
body>
html>
说明:在前面的选择器中,我们通通都是使用DOM提供的方法来获取元素,但这些方法逻辑性不强且繁琐。为此,Js还提供了利用节点层级来获取元素。
| 方法 | 描述 |
|---|---|
| 元素节点.parentNode | 返回元素的父节点。 |
| 元素节点.parentElement | 返回元素的父元素。 |
| 元素节点.childNodes | 返回元素的一个子节点的数组(包含空白文本Text节点)。 |
| 元素节点.children | 返回元素的一个子元素的集合(不包含空白文本Text节点)。但其为非标准方法 |
| 元素节点.firstChild | 返回元素的第一个子节点(包含空白文本Text节点)。 |
| 元素节点.firstElementChild | 返回元素的第一个子元素(不包含空白文本Text节点)。 |
| 元素节点.lastChild | 返回元素的最后一个子节点(包含空白文本Text节点)。 |
| 元素节点.lastElementChild | 返回元素的最后一个子元素(不包含空白文本Text节点)。 |
| 元素节点.previousSibling | 返回某个元素紧接之前节点(包含空白文本Text节点)。 |
| 元素节点.previousElementSibling | 返回指定元素的前一个兄弟元素(相同节点树层中的前一个元素节点)。 |
| 元素节点.nextSibling | 返回某个元素紧接之后节点(包含空白文本Text节点)。 |
| 元素节点.nextElementSibling | 返回指定元素的后一个兄弟元素(相同节点树层中的下一个元素节点)。 |
<div>我是divdiv>
<span>我是spanspan>
<ul>
<li>我是lili>
<li>我是lili>
<li>我是lili>
ul>
<div class="box">
<span class = "erweima">×span>
div>
<script>
// 1.通过已知元素节点获取最近的父节点
var erweima = document.querySelector('.erweima')
// var box = document.querySelector('.box') 传统写法
var box = erweima.parentNode //元素导航写法
console.log(box);
// 2.通过已知元素节点获取所有的子节点,子节点中既有元素节点也有文本节点
// 通常不建议使用该方法来获取子节点,因为太麻烦了
var ul = document.querySelector('ul')
console.log(ul.childNodes);
// 3.非标准方法,但其获得所有浏览器认可,用于选取已知元素节点的所有子元素节点
console.log(ul.children);
// 4.获取第一个子节点
console.log(ul.firstChild);
// 5.获取第一个元素子节点
console.log(ul.firstElementChild);
// 6.获取最后一个子节点
console.log(ul.lastChild);
// 7.获取最后一个元素子节点
console.log(ul.lastElementChild);
script>
| 属性 | 说明 |
|---|---|
| document.anchors | 返回拥有 name 属性的所有 元素 |
| document.baseURI | 返回文档的绝对基准 URI |
| document.body | 返回 元素 |
| document.cookie | 返回文档的 cookie |
| document.doctype | 返回文档的 doctype |
| document.documentElement | 返回 元素 |
| document.documentMode | 返回浏览器使用的模式 |
| document.documentURI | 返回文档的 URI |
| document.domain | 返回文档服务器的域名 |
| document.forms | 返回所有 |
| document.embeds | 返回所有 |
| document.images | 返回所有 |
| document.lastModified | 返回文档更新的日期和时间 |
| document.title | 返回 |
| document.scripts | 返回所有 |