目录
WebAPI背景知识
什么是WebAPI
前面学习的 JS 分成三个大的部分
- ECMAScript: 基础语法部分
- DOM API: 操作页面结构
- BOM API: 操作浏览器
WebAPI 就包含了 DOM + BOM.
这个是 W3C 组织规定的. (和制定 ECMAScript 标准的大佬们不是一伙人).
前面学的 JS 基础语法主要学的是 ECMAScript, 这让我们建立基本的编程思维. 相当于练武需要先扎马步.
但是真正来写一个更加复杂的有交互式的页面, 还需要 WebAPI 的支持. 相当于各种招式.
什么是 API
API 是一个更广义的概念. 而 WebAPI 是一个更具体的概念, 特指 DOM+BOM
所谓的 API 本质上就是一些现成的函数/对象, 让程序猿拿来就用, 方便开发.
相当于一个工具箱. 只不过程序猿用的工具箱数目繁多, 功能复杂.
DOM基本概念
什么是 DOM
DOM 全称为 Document Object Model. 就是文档对象模型.
HTML的每个标签 都是可以映射到JS中的一个对应对象的.
- 标签上显示什么, 都可以通过JS对象感知到.
- JS对象修改对应属性, 能够影响到标签的展示.
通过DOM就可以让JS代码来操作页面元素.
W3C 标准给我们提供了一系列的函数, 让我们可以操作:
- 网页内容
- 网页结构
- 网页样式
DOM API有很多, 这里只介绍几个最常用的.
选中页面元素
CSS中的选择器可以选中页面元素, 然后就可以给这些元素指定页面样式. 那么在JS中的选中页面元素和CSS类似, 通过querySelector方法, 参数传CSS选择器, 此时函数返回结果就是具体的DOM对象.
<div class="box">abc</div>
<div id="id">def</div>
<h3>
<span>
<input type="text">
</span>
</h3>
<script>
let elem1 = document.querySelector('.box');
console.log(elem1);
document: 浏览器中的全局对象. 任何一个页面都会有一个document对象, 所有的DOM API都是通过document对象来展开的.
运行结果:
以下语句会把对象及其属性打印出来:
console.dir(elem1);
其他样式选择器参数
let elem2 = document.querySelector('#id');
console.log(elem2);
let emem3 = document.querySelector('h3>span>input');
console.log(emem3);
注: 如果有多个相同标签, 会默认选中第一个. 如果想全部选出来, 就使用querySelectorAll.
<div class="box">abc</div>
<div id="id">def</div>
<script>
var elems = document.querySelectorAll('div');
console.log(elems);
</script>
事件
基本概念
事件就是针对用户的操作进行的一些响应. 我们要能够和用户交互, 就需要知道用户干了啥. 那么用户做的一些动作, 就会在浏览器中产生一些事件. 接下来代码就需要针对事件做出一些反应.
事件有很多种, 比如说, 鼠标点击, 鼠标双击, 鼠标移动, 键盘按下, 调整浏览器窗口....
事件三要素
1. 事件源: 哪个元素产生的事件
2. 事件类型: 是点击, 选中, 还是修改?
3. 事件处理程序: 事件发生之后, 要执行哪个代码. (要执行的代码都是提前设定好的).往往是一个回调函数.
简单示例
<button id="btn">点我一下</button>
<script>
var btn = document.getElementById('btn');
btn.onclick = function () {
alert("hello world");
}
</script>
- btn 按钮就是事件源.
- 点击就是事件类型
- function 这个匿名函数就是事件处理程序
- 其中 btn.onclick = function() 这个操作称为 注册事件/绑定事件
注意: 这个匿名函数相当于一个回调函数, 这个函数不需要程序猿主动来调用, 而是交给浏览器, 由浏览器自动在合适的时机(触发点击操作时) 进行调用.
操作元素
获取 / 修改元素内容
先获取到该元素, 使用innerHTML属性就能拿到元素里的内容.
修改该属性, 就会直接影响到界面的显示.
<div class="box">abc</div>
<div id="id">def</div>
<h3>
<span>
<input type="text">
</span>
</h3>
<script>
let div = document.querySelector('.box');
div.onclick = function() {
console.log(div.innerHTML);
}
</script>
点击abc, 可以看到控制台的abc打印了, 并且abc之前的数字不断增加(注: Chrome控制台会默认把相同的日志合并.)
let div = document.querySelector('.box');
div.onclick = function() {
console.log(div.innerHTML);
div.innerHTML += 'a';
}
运行结果中不断点击abc, 可以看到每点击一次, 这里的a都会多出一个, 那么这里的操作就是上述代码的+=代码. 而对于HTML来说+=就是字符串+=, 就是在尾部进行拼接.
所以要想影响到页面的显示, 就可以修改innerHTML属性.
获取/修改元素属性
HTML标签的属性, 也会映射到JS对象中. 也就是说标签里有什么属性, JS中也会对应有一些属性.
<img src="微信截图_20230411195311.png" alt="">
<script>
let img = document.querySelector('img');
img.onclick = function() {
console.log(img.src);
console.log(img.alt);
console.log(img.title);
console.log(img.width);
console.log(img.height);
img.src = 'T.png';
}
</script>
运行结果: 点击图片, 会变成T.png
获取/修改表单元素属性
表单元素(input, textarea, select...)有一些特别的属性是普通标签没有的.
value:
<input type="text">
<button>点我一下</button>
<script>
let input = document.querySelector('input');
let button = document.querySelector('button');
button.onclick = function() {
console.log(input.value);
}
</script>
注: innerHTML得到的是标签的内容(开始标签结束标签中间夹着的部分). input标签是单个属性, 没有内容.
给input里放个数字, 每次点击按钮, 让数字+1, 并显示出来.
<input type="text">
<button>点我一下</button>
<script>
let input = document.querySelector('input');
let button = document.querySelector('button');
button.onclick = function() {
let value = input.value;
value += 1;
input.value = value;
}
</script>
要注意, 当前value属性是string, 此时的话直接+1就变成字符串拼接. 所以添加函数把字符串改成整数.
let value = parseInt(input.value);
type: 切换密码是否显示
<input type="text">
<button>隐藏密码</button>
<script>
let input = document.querySelector('input');
let button = document.querySelector('button');
button.onclick = function() {
if (input.type == 'text') {
input.type = 'password';
button.innerHTML = '显示密码';
} else {
input.type = 'text';
button.innerHTML = '隐藏密码';
}
}
</script>
获取/修改样式属性
- 修改内联样式(修改style属性的值)
element.style.[属性名] = [属性值];
element.style.cssText = [属性名+属性值];
"行内样式", 通过 style 直接在标签上指定的样式. 优先级很高.
适用于改的样式少的情况
搞一个div, 每次点击, 都让里面的字体放大.
<div style="font-size: 20px;">这是一个div, 点击之后字体放大</div>
<script>
let div = document.querySelector('div');
div.onclick = function() {
//获取当前字体大小
let fontSize = parseInt(div.style.fontSize);
fontSize += 10;
//设置字体大小时注意单位 px !
div.style.fontSize = fontSize + 'px';
}
</script>
- 修改元素应用的CSS类名.
element.className = [CSS 类名];
例: 切换夜间模式
<div id="one" class="light" style="font-size: 20px; height: 500px;">这是一个div, 点击之后改变模式</div>
<style>
.light {
/* 日间模式*/
color: black;
background-color: white;
}
.dark {
/* 夜间模式*/
color: white;
background-color: black;
}
</style>
<script>
let div = document.querySelector('#one');
div.onclick = function() {
if (div.className == 'dark') {
div.className = 'light';
} else {
div.className = 'dark';
}
}
</script>
上述操作都是针对于当前页面上已有的元素进行展开的, 那么我们也是可以创建元素, 还有删除元素.
操作节点
新增节点
分成两个步骤
1. 创建元素节点
2. 把元素节点插入到 dom 树中.
在这里面创建元素使用的是createElement方法, 然后使用appendChild加入到子元素的末尾.
<div class="one">
这是一个div
</div>
<script>
let input = document.createElement('input');
//让输入框里默认显示 hello 这个内容
input.value = 'hello';
let div = document.querySelector('.one');
div.appendChild(input);
</script>
这里的添加元素不止只能添加一个元素.
<ul>
<li>11</li>
<li>22</li>
</ul>
<script>
let ul = document.querySelector('ul');
for (let n = 3; n < 10; n++) {
let li = document.createElement('li');
li.innerHTML = n + '' + n;
ul.appendChild(li);
}
</script>
另注: insertBefore可以把元素加到指定子元素的前面(相当于中间位置插入)
删除元素
使用 removeChild 删除子节点
oldChild = parentElem.removeChild(childElem);
- childElem 为待删除节点
- parentElem 为 childElem 的父节点
- 返回值为该被删除节点
- 被删除节点只是从 dom 树被删除了, 但是仍然在内存中, 可以随时加入到 dom 树的其他位置.
- 如果上例中的 childElem节点 不是 parentElem 节点的子节点,则该方法会抛出异常.
//删除 33 这个元素
let toDelete = document.querySelectorAll('li')[2];
console.log(toDelete);
ul.removeChild(toDelete);
代码案例: 猜数字
- 生成 1-100 之间的随机数
- 让用户输入一个数字
- 根据输入数字的大小关系, 给出提示 高了/ 低了/ 猜对了
注:
Math.random() 生成的是[0, 1) 之间的随机数, 设随机数为N
N的范围是[0, 1), 100 * N 的范围[0, 100), 由于这是一个很长的小数, 那么使用parseInt把小数部分去掉, 得到 [0, 100) 的整数 即 [0, 99] 之间的整数, 再+1 就是[1, 100].
<div>请输入要猜的数字</div>
<input type="text">
<button>提交</button>
<!-- 使用这个div来显示结果 -->
<div class="result">
</div>
<script>
//1. 生成一个1-100的随机整数
let toGuess = parseInt(100 * Math.random()) + 1;
console.log(toGuess);
//2. 进行猜数字操作
let button = document.querySelector('button');
let input = document.querySelector('input');
let resultDiv = document.querySelector('.result');
button.onclick = function() {
//3. 取出输入框中的内容
if (input.value == ''){
//没有输入任何内容, 直接返回
return;
}
let inputNum = parseInt(input.value);
//4. 比较大小关系
if (inputNum < toGuess){
//低了
resultDiv.innerHTML = '低了';
} else if (inputNum > toGuess){
//高了
resultDiv.innerHTML = '高了';
} else {
//猜对了
resultDiv.innerHTML = '猜对了';
}
}
</script>
代码案例: 表白墙
预期效果
<!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>Document</title>
<style>
* {
/* 消除浏览器的默认样式 */
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
width: 600px;
margin: 20 auto;
}
h1 {
text-align: center;
}
p {
text-align: center;
color: #666;
margin: 20px 0;
}
.row {
display: flex;
height: 40px;
justify-content: center;
align-items: center;
}
.row span {
width: 80px;
}
.row input {
width: 200px;
height: 30px;
}
.row button {
width: 280px;
height: 30px;
color: white;
background-color: orange;
border: none;
border-radius: 5px;
}
.row button:active {
background-color: grey;
}
</style>
</head>
<body>
<div class="container">
<h1>表白墙</h1>
<p>输入内容后点击提交, 信息会显示到下方表格中</p>
<div class="row">
<span>谁:</span>
<input type="text">
</div>
<div class="row">
<span>对谁:</span>
<input type="text">
</div>
<div class="row">
<span>说什么:</span>
<input type="text">
</div>
<div class="row">
<button id="submit">提交</button>
</div>
<div class="row">
<button id="revert">撤销</button>
</div>
</div>
<script>
// 实现提交操作, 点击提交按钮, 就能够把用户输入的内容提交到页面上显示
// 点击的时候, 获取到三个输入框中的文本内容
// 创建一个新的 div.row 把内容构造到这个 div 中即可
let containerDiv = document.querySelector('.container');
let inputs = document.querySelectorAll('input');
let button = document.querySelector('#submit');
button.onclick = function() {
//1. 获取到三个输入框的内容
let from = inputs[0].value;
let to = inputs[1].value;
let msg = inputs[2].value;
if (from == '' || to == '' || msg == ''){
return;
}
//2. 构造新 div
let rowDiv = document.createElement('div');
rowDiv.className = 'row message';
rowDiv.innerHTML = from + ' 对' + to + ' 说:' + msg;
containerDiv.appendChild(rowDiv);
//3. 清空之前的输入框内容
for (let input of inputs) {
input.value = '';
}
}
let revertButton = document.querySelector("#revert");
revertButton.onclick = function() {
//删除最后一条消息
//选中所有的row, 找到最后一个row, 然后进行删除
let rows = document.querySelectorAll('.message');
if (rows == null || rows.length == 0){
return;
}
containerDiv.removeChild(rows[rows.length - 1]);
}
</script>
</body>
</html>