1. WebAPI 背景知识
1.1 API 基本介绍
API(Application Programming Interface 应用程序接口): 是一些预先定义的接口(如函数、HTTP 接口)或指软件系统不同组成部分衔接的约定。用来提供应用程序与开发人员基于某软件或硬件得以访问的一组例程,而又无需访问源码,或理解内部工作机制的细节。
1.2 WebAPI 基本介绍
在《【Web 三件套】JavaScript 入门知识》 这章中介绍了 JS 基本分成三个部分
- ECMAScript(简称 ES):是 JavaScript 的语法
- DOM(Document Object Model):文档对象模型,用于对页面中的元素进行操作。(页面上的每个 HTML 元素,都在 JS 中对应到一个对象,通过 JS 操作这些对象,就可以达到控制页面表现形式的效果)
- BOM(Browser Object Model):浏览器对象模型,用于对浏览器窗口进行操作。(浏览器也在 JS 中提供了一些对象,例如:刷新页面、控制浏览器窗口大小、前进、后退等等,通过 JS 操作这些对象就可以控制浏览的一些行为)
WebAPI 就包含了 DOM 和 BOM,下面着重介绍几个常用的接口,更详细的内容可以参考 WebAPI 接口参考文档
WebAPI 接口参考文档: https://developer.mozilla.org/zh-CN/docs/Web/API
2. DOM 基本概念
2.1 DOM 基本介绍
DOM(Document Object Model 文档对象模型): 是 W3C 组织推荐的处理可扩展置标语言的标准编程接口。它是一种与平台和语言无关的应用程序接口(API),它可以动态地访问程序和脚本、更新其内容、结构和 www 文档的风格(HTML 和 XML 文档是通过说明部分定义的)。文档可以进一步被处理,处理的结果可以加入到当前的页面。DOM 是一种基于树的 API 文档,它要求在处理过程中整个文档都表示在存储器中。
重要概念:
- 文档(document):一个页面就是一个文档
- 元素(element):页面中所有的标签都称为元素
- 节点(node):网页中所有的内容都可以称为节点,如标签节点、注释节点、文本节点、属性节点
上述文档等概念在 JS 代码中就对应一个个对象,所以称为文档对象模型
2.2 DOM 树
基本介绍: DOM 是一种基于树的 API 文档,由于一个页面的结构是一个树形结构,称其为 DOM 树。
注意: DOM 树不是所有的标签的集合,而是根据当前页面的情况,由于每个页面的情况不一样,每个页面的 DOM 树则不一样
页面结构形如:
DOM 树结构形如:
3 获取元素
3.1 querySelector
基本介绍:
文档对象模型 Document
引用的 querySelector()
方法返回文档中与指定选择器或选择器组匹配的第一个 Element
对象。 如果找不到匹配项,则返回 null
语法:
let element = document.querySelector(selectors);
selectors 参数:
包含一个或多个要匹配的选择器的 DOM 字符串 DOMString。该字符串必须是有效的 CSS 选择器字符串;如果不是,则引发 SYNTAX_ERR
异常。
示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<input type="text" id="number" value="0">
<input type="button" id="button" value="自增">
<script>
// 获取第一个 id 名为 number 的对象
let number = document.querySelector('#number');
// 使用 dir 打印一个元素对象, 此时就能看到里面的具体属性
console.dir(number)
</script>
</body>
</html>
3.2 querySelectorAll
基本介绍: 返回与指定的选择器组匹配的文档中的元素列表 (使用深度优先的先序遍历文档的节点)。返回的对象是 NodeList
。与 querySelector
不同,querySelectorAll
方法返回文档中与指定选择器或选择器组匹配的全部 Element
对象。
语法:
let elementList = document.querySelectorAll(selectors);
selectors 参数:
一个 DOMString
包含一个或多个匹配的选择器。这个字符串必须是一个合法的 CSS 选择器,如果不是,会抛出一个 SyntaxError
错误。
示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<input type="text" id="number" value="0">
<input type="button" id="button" value="自增">
<script>
// 获取选择器为 input 的全部对象
let inputs = document.querySelectorAll('input');
// 使用 log 打印一个元素对象, 此时看到的是 html 片段
console.log(inputs);
</script>
</body>
</html>
NodeList 介绍:
NodeList
对象是节点的集合,通常是由属性,如Node.childNodes
和方法,如document.querySelectorAll
和方法,如document.querySelectorAll
返回的。NodeList
不是一个数组,是一个类似数组的对象。虽然NodeList
不是一个数组,但是可以使用forEach()
来迭代。你还可以使用Array.from()
将其转换为数组。
4. 事件介绍
4.1 基本概念
基本介绍:
-
事件是你在编程时系统内发生的动作或者发生的事情,系统响应事件后,如果需要,您可以某种方式对事件做出回应。例如:如果用户在网页上单击一个按钮,您可能想通过显示一个信息框来响应这个动作。
-
在 Web 中, 事件在浏览器窗口中被触发并且通常被绑定到窗口内部的特定部分,可能是一个元素、一系列元素、被加载到这个窗口的 HTML 代码或者是整个浏览器窗口
-
每个可用的事件都会有一个事件处理器,也就是事件触发时会运行的代码块。当我们定义了一个用来回应事件被激发的代码块的时候,我们说我们注册了一个事件处理器。注意事件处理器有时候被叫做事件监听器
4.2 事件三要素
- 事件源:哪个元素触发的
- 事件类型:是点击、选中或修改
- 事件处理程序:进一步如何处理(往往通过一个回调函数处理)
4.3 点击事件
基本介绍:
点击事件是最常用的事件,当我们找到事件源后(任意 HTML 元素都能触发点击事件),可以使用点击事件,再用一个回调函数来处理我们获取的对象
语法:
element.onclick = function() {
// 处理事件
}
- element 表示事件源
- conclick 表示点击事件
- function 表示使用匿名对象来处理该程序,相当于一个回调函数,由浏览器在合适的实机进行调用
element.onclick = function()
这个操作表示注册事件/绑定事件
示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<input type="text" id="number" value="0">
<input type="button" id="submit" value="自增">
<script>
// 获取第一个 id 名为 submit 的对象
let submitButton = document.querySelector('#submit');
// 使用点击事件处理 number 对象
submitButton.onclick = function() {
// 处理事件
console.log('用户点击了按钮')
}
</script>
</body>
</html>
5. 操作元素
5.1 获取/修改元素内容
-
方式一: innerHTML
基本介绍: innerHTML 属性设置或获取 HTML 语法表示的元素的后代
语法:
element.innerHTML = htmlString;
注意:
- 设置元素的
innerHTML
将会删除所有该元素的后代并以上面给出的 htmlString 替代。 - innerHTML 可以获取该标签中的文本以及嵌套在内的标签
- 由于 innerHTML 修改的是标签里的内容,而表单标签(如 input)是一个单标签,因此不能使用 innerHTML 修改如 input 标签中的 value 值
示例代码:
<!DOCTYPE html> <html lang="en"> <head> <title>Document</title> </head> <body> <div>按钮弹起</div> <script> let div = document.querySelector('div'); div.onclick = function() { if(div.innerHTML == '按钮弹起') { div.innerHTML = '按钮按下'; }else if(div.innerHTML == '按钮按下') { div.innerHTML = '按钮弹起' } } </script> </body> </html>
- 设置元素的
-
方式二: innerText
基本介绍: innerText 属性设置或获取一个节点及其后代的“渲染”文本内容
语法:
element.innerText = string;
注意: innerText 只能修改该标签内的文本
示例代码:
<!DOCTYPE html> <html lang="en"> <head> <title>Document</title> </head> <body> <div>按钮弹起</div> <script> let div = document.querySelector('div'); div.onclick = function() { if(div.innerText == '按钮弹起') { div.innerText = '按钮按下'; }else if(div.innerText == '按钮按下') { div.innerText = '按钮弹起' } } </script> </body> </html>
5.2 获取/修改元素属性
方式: 可以通过 对象.属性
的方式直接获取或修改元素的属性
注意: 可以通过 console.dir
来查看该元素的属性
示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<img src="image/background.jpg" title="背景图">;
<script>
let img = document.querySelector('img');
img.onclick = function() {
console.log(img.src);
img.src = 'image/log.png';
img.title = '图标';
}
</script>
</body>
</html>
5.3 获取/修改表单元素属性
介绍: 表单(主要是指 input 标签)的以下属性都可以通过 DOM 来修改
属性 | 描述 |
---|---|
value | input 的值 |
disabled | 禁用 |
checked | 复选框会使用 |
selected | 下拉框会使用 |
type | input 的类型(文本/密码/按钮/文件等) |
方式: 可以通过 对象.属性
的方式直接获取或修改元素的属性
示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<input type="password" id="password">
<input type="button" id="button" value="显示密码">
<script>
let button = document.querySelector('#button');
button.onclick = function() {
let input = document.querySelector('#password');
if(button.value == '显示密码') {
button.value = '隐藏密码';
input.type = 'text';
}else if(button.value == '隐藏密码') {
button.value = '显示密码';
input.type = 'password';
}
}
</script>
</body>
</html>
5.4 获取/修改样式属性
CSS 中指定给元素的属性,都可以通过 JS 来修改,以下介绍两种样式的操作方式
-
行内样式操作
介绍: style 是一个对象的属性,也可以是一个对象,因此里面存放了当前元素上面的行内样式
操作语法:
// 方式一 element.style.属性名 = 属性值; // 方式二 element.style.cssText = 属性名+属性值;
示例代码:
<!DOCTYPE html> <html lang="en"> <head> <title>Document</title> </head> <body> <div style="font-size: 20px;">肉蛋冲击</div> <script> let div = document.querySelector('div'); div.onclick = function() { let fontSize = parseInt(div.style.fontSize); fontSize += 5; div.style.fontSize = fontSize + 'px'; } </script> </body> </html>
-
类名样式操作
介绍: 当样式复杂时,涉及到很多个属性操作,通过 CSS 里面的类就可以达到一次赋值来设置多个 CSS 属性,只要把 CSS 类名设置上去,此时这个类里面的属性就会被应用到当前元素上
操作语法:
element.className = CSS 类名;
示例代码:
<!DOCTYPE html> <html lang="en"> <head> <title>Document</title> <style> .light { background-color: white; color: black; } .dark { background-color: black; color: white; } </style> </head> <body> <div class="light"> 肉蛋冲击 <br> 肉蛋冲击 <br> 肉蛋冲击 <br> 肉蛋冲击 <br> 肉蛋冲击 <br> </div> <script> let div = document.querySelector('div'); div.onclick = function() { if(div.className == 'light') { div.className = 'dark'; }else if(div.className == 'dark') { div.className = 'light'; } } </script> </body> </html>
6. 操作节点
6.1 新增节点
基本介绍: document.createElement()
方法用于创建一个由标签名称 tagName 指定的 HTML 元素。如果用户代理无法识别 tagName,则会生成一个未知 HTML 元素 HTMLUnknownElement
语法:
let element = document.createElement(tagName);
tagName 参数:
指定要创建元素类型的字符串,创建元素时的 nodeName
使用 tagName
的值为初始化,该方法不允许使用限定名称(如 :“html:a”),在 HTML 文档上调用 createElement()
方法创建元素之前会将 tagName
转化成小写,在 Firefox、Opera 和 Chrome 内核中,createElement(null)
等同于 createElement("null")
注意: 通过 createElement 创建出来的元素不会直接显示在页面上,因为页面内容都是在 DOM 树上的,但是新创建的元素没有挂到 DOM 树上
示例代码:
let div = document.createElement('div');
div.innerHTML = '肉蛋冲击';
div.style.fontSize = '30px';
6.2 把新增节点插入到 DOM 树
基本介绍: 将新增的元素插入到 DOM 树上,这里有两种方式
-
方式一: 使用
appendChild
将节点插入到指定节点的最后一个孩子节点后面介绍:
Node.appendChild()
方法将一个节点附加到指定父节点的子节点列表的末尾处。如果将被插入的节点已经存在于当前文档的文档树中,那么appendChild()
只会将它从原先的位置移动到新的位置(不需要事先移除要移动的节点)。语法:
element.appendChild(aChild)
aChild 参数:
要追加给父节点(通常为一个元素)的节点。
示例代码:
let div = document.createElement('div'); div.innerHTML = '肉蛋冲击'; div.style.fontSize = '30px'; let body = document.querySelector('body'); body.appendChild(div);
-
方式二: 使用
insertBefore
将节点插入到指定节点之前介绍:
Node.insertBefore()
方法在参考节点之前插入一个拥有指定父节点的子节点。如果给定的子节点是对文档中现有节点的引用,insertBefore()
会将其从当前位置移动到新位置(在将节点附加到其他节点之前,不需要从其父节点删除该节点)。语法:
parentNode.insertBefore(newNode, referenceNode);
参数:
- parentNode:新插入节点的父节点
- newNode:用于插入的节点
- referenceNode:新插入节点将要插在这个节点之前
注意: 如果 referenceNode 为 null,则 newNode 将被插到子节点的末尾
示例代码:
<!DOCTYPE html> <html lang="en"> <head> <title>Document</title> </head> <body> <div class="container"> <div class="one">11111</div> <div class="two">22222</div> </div> <script> let div = document.createElement('div'); div.innerHTML = '33333'; let container = document.querySelector('.container'); let two = document.querySelector('.two'); container.insertBefore(div, two); </script> </body> </html>
6.3 删除节点
基本介绍: Node.removeChild()
方法从 DOM 中删除一个子节点。返回删除的节点。
语法:
element.removeChild(child);
参数:
- element 为待删除节点的父节点
- child 为待删除节点
- 该函数有返回值,为被删除节点
注意: 被删除节点只是从 DOM 树被删除了,但是任然在内存中,可以随时加入到 DOM 树的其它位置
示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<div class="container">
<div class="one">11111</div>
<div class="two">22222</div>
</div>
<script>
let container = document.querySelector('.container');
let two = document.querySelector('.two');
container.removeChild(two);
</script>
</body>
</html>
7. 案例
7.1 猜数字
样例展示:
样例代码:
<!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>猜数字游戏</title>
</head>
<body>
<input type="button" value="重新开始一局游戏" id="restart">
<div>
<span>请输入要猜的数字:</span>
<input type="text" id="num">
<input type="button" value="猜" id="guess">
</div>
<div>
<span>已经猜的次数: </span>
<span id="count">0</span>
</div>
<div>
<span>结果: </span>
<span id="result"></span>
</div>
<script>
// 先把需要用到的 JS 的 DOM 对象准备好
let restartButton = document.querySelector('#restart');
let numInput = document.querySelector('#num');
let guessButton = document.querySelector('#guess');
let countSpan = document.querySelector('#count');
let resultSpan = document.querySelector('#result');
// 生成一个 1-100 之间的随机整数
let toGuess = Math.floor(Math.random() * 100) + 1;
let count = 0;
console.log("toGuess: " + toGuess);
guessButton.onclick = function() {
// 用户点击 猜 这个按钮,首先更新点击次数的显示
count++;
countSpan.innerHTML = count;
let num = parseInt(numInput.value);
if(num < toGuess) {
resultSpan.innerHTML = '数字猜小了!';
}else if(num > toGuess) {
resultSpan.innerHTML = '数字猜大了!';
}else {
resultSpan.innerHTML = '恭喜你猜对了!';
}
}
restartButton.onclick = function() {
// 把 toGuess 和 count 清空,重新生成一个随机的整数
toGuess = Math.floor(Math.random() * 100) + 1;
count = 0;
console.log("toGuess: " + toGuess);
countSpan.innerHTML = count;
resultSpan.innerHTML = '';
}
</script>
</body>
</html>
7.2 表白墙
样例展示:
样例代码:
<!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>表白墙</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
width: 600px;
margin: 0 auto;
}
h1 {
text-align: center;
padding: 20px 0;
color: pink;
}
p {
text-align: center;
font-size: 15px;
color: grey;
padding: 5px 0;
}
.row {
display: flex;
height: 40px;
justify-content: center;
align-items: center;
}
.row span {
width: 80px;
}
.row .edit {
width: 250px;
height: 35px;
}
.row .submit {
width: 330px;
height: 40px;
background-color: orange;
color: #fff;
border: none;
}
.row .submit:active {
background-color: grey;
}
</style>
</head>
<body>
<div class="container">
<h1>表白墙</h1>
<p>输入后点击提交,将会把消息显示在在墙上</p>
<div class="row">
<span>谁:</span>
<input type="text" class="edit">
</div>
<div class="row">
<span>对谁:</span>
<input type="text" class="edit">
</div>
<div class="row">
<span>说什么:</span>
<input type="text" class="edit">
</div>
<div class="row">
<input type="button" value="提交" class="submit">
</div>
</div>
<script>
let submitButton = document.querySelector('.submit');
submitButton.onclick = function() {
// 1. 获取到输入框里的内容
let edits = document.querySelectorAll('.edit');
// 2. 根据输入框的内容,构造 HTML 元素,添加到页面中
let message = edits[0].value + "对" + edits[1].value + "说: " + edits[2].value;
if(edits[0].value == '' || edits[1].value == '' || edits[2].value == '') {
return;
}
let div = document.createElement('div');
div.innerHTML = message;
div.className = 'row';
let container = document.querySelector('.container');
container.appendChild(div);
// 3. 把上次输入的内容清空
for(let i = 0; i < edits.length; i++){
edits[i].value = '';
}
}
</script>
</body>
</html>
7.3 待办事项
样例展示:
样例代码:
<!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>待办事项</title>
</head>
<body>
<style>
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
.nav {
width: 600px;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: center;
margin-top: 10px;
}
.nav input {
width: 450px;
height: 50px;
font-size: 25px;
padding-left: 10px;
}
.nav button {
width: 150px;
height: 50px;
border: none;
color: white;
background-color: orange;
font-size: 18px;
}
.nav button:active {
background-color: grey;
}
.container {
width: 600px;
margin: 0 auto;
display: flex;
justify-content: center;
/* padding-top: 10px; */
margin-top: 10px;
/* background-color: green; */
}
.container .left,
.container .right {
width: 50%;
}
.container .left h3,
.container .right h3 {
text-align: center;
height: 50px;
line-height: 50px;
background-color: black;
color: white;
}
.container .row {
height: 50px;
display: flex;
align-items: center;
justify-content: flex-start;
}
.container .row span {
width: 240px;
}
.container .row button {
width: 40px;
height: 30px;
}
.container .row input {
margin-right: 5px;
}
</style>
<!-- 表示上方的 div, 里面放输入框和按钮 -->
<div class="nav">
<input type="text">
<button>新建任务</button>
</div>
<!-- 这个是下方的 div, 里面分成左右两栏 -->
<div class="container">
<div class="left">
<h3>未完成</h3>
<!-- <div class="row">
<input type="checkbox">
<span>吃饭</span>
<button>删除</button>
</div> -->
</div>
<div class="right">
<h3>已完成</h3>
</div>
</div>
<script>
let addTaskBtn = document.querySelector(".nav button");
addTaskBtn.onclick = function() {
// 1. 获取到输入框的内容
let input = document.querySelector(".nav input");
let taskContent = input.value;
// 2. 创建一个 div.row, 里面设置上需要的 复选框, 文本, 删除按钮
let row = document.createElement('div');
row.className = 'row';
let checkBox = document.createElement('input');
checkBox.type = 'checkbox';
let span = document.createElement('span');
span.innerHTML = taskContent;
let deleteBtn = document.createElement('button');
deleteBtn.innerHTML = '删除';
row.appendChild(checkBox);
row.appendChild(span);
row.appendChild(deleteBtn);
// 3. 把 div.row 添加到 .left 中~
let left = document.querySelector('.left');
left.appendChild(row);
// 4. 给 checkBox 增加一个点击处理函数. 点击之后就能够移动任务
checkBox.onclick = function() {
// 当用户点击的时候, 就获取到当前的这个 row 这个元素
// 把这 row 给添加到另外一侧.
// 也可以根据 checkBox 的选中状态决定是在 left 还是 right
let target = null;
if (checkBox.checked) {
// 已经是选中的状态
// 就把这个元素放到右边
target = document.querySelector('.right');
} else {
// 是未选中的状态
// 就把这个元素放到左边
target = document.querySelector('.left');
}
target.appendChild(row);
}
// 5. 实现删除效果, 给删除按钮新增一个删除操作
deleteBtn.onclick = function() {
// 要想删除 row, 就需要知道 row 的父元素
let parent = row.parentNode;
parent.removeChild(row);
}
}
</script>
</body>
</html>