什么是WebAPI
- JS主要分成的三个部分:
- ECMAScript: 基础语法部分
- DOM API: 操作页面结构
- BOM API: 操作浏览器
WebAPI 就包含了 DOM + BOM,而 API 我们可以通俗理解为一个工具箱,里面有我们能用到的函数/对象…
什么是DOM
DOM 全称为 Document Object Model
W3C 标准给我们提供了一系列的函数, 让我们可以操作:
网页内容
网页结构
网页样式
DOM树
一个页面的结构是一个树形结构, 称为 DOM 树
DOM 树结构形如
重要概念:
文档: 一个页面就是一个 文档, 使用 document 表示.
元素: 页面中所有的标签都称为 元素. 使用 element 表示.
节点: 网页中所有的内容都可以称为 节点(标签节点, 注释节点, 文本节点, 属性节点等). 使用 node表示.这些文档等概念在 JS 代码中就对应一个个的对象
DOM API:
浏览器给JS 提供的一组用来操作 页面元素 的API
1:获取元素:(querySelector / querySelectorAll…)
2:事件处理:(onclick…)
3:操作元素内容:(innerHTML…)
获取元素
querySelector
var element = document.querySelector(selectors);
<body>
<div class="box">hello</div>
<div id="id">world</div>
<h3><span><input type="text"></span></h3>
<script>
var elem1 = document.querySelector('.box');
console.log(elem1);
var elem2 = document.querySelector('#id');
console.log(elem2);
var elem3 = document.querySelector('h3 span input');
console.log(elem3);
</script>
</body>
querySelectorAll
<div class="box">hello</div>
<div id="id">world</div>
<script>
var elems = document.querySelectorAll('div');
console.log(elems);
</script>
事件
JS 要构建动态页面, 就需要感知到用户的行为.
用户对于页面的一些操作(点击, 选择, 修改等) 操作都会在浏览器中产生一个个事件, 被 JS 获取到, 从而进行更复杂的交互操作.
事件三要素:
- 事件源: 哪个元素触发的
- 事件类型: 是点击, 选中, 还是修改?
- 事件处理程序: 进一步如何处理. 往往是一个回调函数
<button id="btn">点我一下</button>
<script>
var btn = document.getElementById('btn');
btn.onclick = function () {
alert("hello world");
}
</script>
btn 按钮就是事件源.
点击就是事件类型
function 这个匿名函数就是事件处理程序
其中 btn.onclick = function() 这个操作称为 注册事件/绑定事件
操作元素
innerText:
Element.innerText 属性表示一个节点及其后代的“渲染”文本内容
读操作 var renderedText = HTMLElement.innerText;
写操作 HTMLElement.innerText = string;
<div class="one">hello world</div>
<div class="two">hello world</div>
<script>
var div = document.querySelector('.one');
// 读取 div 内部内容
console.log(div);
</script>
<div class="one">hello world</div>
<div class="two">hello world</div>
<script>
var div = document.querySelector('.one');
// 读取 div 内部内容
console.log(div);
// 修改 div 内部内容, 界面上就会同步修改
div.innerText = '<span>world hello</span>';
</script>
可以看到, 通过 innerText 无法获取到 div 内部的 html 结构, 只能得到文本内容.
修改页面的时候也会把 span 标签当成文本进行设置
innerHTML
Element.innerHTML 属性设置或获取HTML语法表示的元素的后代
读操作
var content = element.innerHTML;
写操作
element.innerHTML = htmlString;
<div class="one">hello world</div>
<div class="two">hello world</div>
<script>
var div = document.querySelector('.one');
console.log(div);
div.innerHTML = '<span>world hello</span>';
</script>
可以看到 innerHTML 不光能获取到页面的 html 结构, 同时也能修改结构. 并且获取到的内容保留的空格和换行…
获取/修改元素属性
可以通过 Element 对象的属性来直接修改, 就能影响到页面显示效果.
我们可以在代码中直接通过这些属性来获取属性的值
<img src="wallhaven-l37662.jpg" alt="这是一只猫" title="灰猫" width="200px">
<script>
var img = document.querySelector('img');
console.dir(img);
console.log(img.src);
console.log(img.title);
console.log(img.alt);
</script>
还可以直接修改属性
<img src="wallhaven-l37662.jpg" alt="这是一只猫" title="灰猫" width="200px">
<script>
var img = document.querySelector('img');
img.onclick = function () {
if (img.src.lastIndexOf('wallhaven-l37662.jpg') !== -1) {
img.src = 'wallhaven-e71ddk.png';
} else {
img.src = 'wallhaven-l37662.jpg';
}
}
</script>
获取/修改表单元素属性
表单(主要是指 input 标签)的以下属性都可以通过 DOM 来修改
value: input 的值.
disabled: 禁用
checked: 复选框会使用
selected: 下拉框会使用
type: input 的类型(文本, 密码, 按钮, 文件等)
切换按钮的文本
<input type="button" value="播放">
<script>
var btn = document.querySelector('input');
btn.onclick = function () {
if (btn.value === '播放') {
btn.value = '暂停';
} else {
btn.value = '播放';
}
}
</script>
点击计数
<input type="text" id="text" value="0">
<input type="button" id="btn" value='点我+1'>
<script>
var text = document.querySelector('#text');
var btn = document.querySelector('#btn');
btn.onclick = function () {
var num = +text.value;
console.log(num);
num++;
text.value = num;
}
</script>
input 具有一个重要的属性 value, 这个 value 决定了表单元素的内容…
如果是输入框, value 表示输入框的内容, 修改这个值会影响到界面显式; 在界面上修改这个值也会影响到代码中的属性…
如果是按钮, value 表示按钮的内容. 可以通过这个来实现按钮中文本的替换…
全选/取消全选按钮
1.点击全选按钮, 则选中所有选项
2. 只要某个选项取消, 则自动取消全选按钮的勾选状态
<h3>请选者喜欢的水果</h3>
<label for="all">
<input type="checkbox" id="all">
<img src="D:\火狐浏览器\卡通图标\全部.png" alt="" width="20px">全喜欢 <br>
</label>
<label for="apple">
<input type="checkbox" class="Fruit" id="apple">
<img src="D:\火狐浏览器\卡通图标\苹果.png" alt="" width="20px">苹果 <br>
</label>
<label for="benlala">
<input type="checkbox" class="Fruit" id="benlala">
<img src="D:\火狐浏览器\卡通图标\香蕉.png" alt="" width="20px">香蕉 <br>
</label>
<label for="huolongguo">
<input type="checkbox" class="Fruit" id="huolongguo">
<img src="D:\火狐浏览器\卡通图标\火龙果.png" alt="" width="20px">火龙果 <br>
</label>
<label for="lizi">
<input type="checkbox" class="Fruit" id="lizi">
<img src="D:\火狐浏览器\卡通图标\梨子.png" alt="" width="20px">梨子 <br>
</label>
<script>
// 1. 获取到元素
var all = document.querySelector('#all');
var Fruits = document.querySelectorAll('.Fruit');
// 2. 给 all 注册点击事件, 选中/取消所有选项
all.onclick = function () {
for (var i = 0; i < Fruits.length; i++) {
Fruits[i].checked = all.checked;
}
}
// 3. 给 Fruit 注册点击事件
for (var i = 0; i < Fruits.length; i++) {
Fruits[i].onclick = function () {
// 检测当前是不是所有的 Fruit 都被选中了.
all.checked = checkFruits(Fruits);
}
}
// 4. 实现 checkFruits
function checkFruits(Fruits) {
for (var i = 0; i < Fruits.length; i++) {
if (!Fruits[i].checked) {
// 只要一个 Fruit 没被选中, 就认为结果是 false(找到了反例)
return false;
}
}
// 所有 Fruit 中都没找到反例, 结果就是全选中
return true;
}
</script>
获取/修改样式属性
CSS 中指定给元素的属性, 都可以通过 JS 来修改.
行内样式操作:
element.style.[属性名] = [属性值];
element.style.cssText = [属性名+属性值]
<div style="font-size: 20px; font-weight: 700; color: rgb(238, 23, 23);">
hello
</div>
<script>
var div = document.querySelector('div');
div.onclick = function () {
var curFontSize = parseInt(this.style.fontSize);
curFontSize += 10;
this.style.fontSize = curFontSize + "px";
}
</script>
类名样式操作:
element.className = [CSS 类名];
开启夜间模式
点击页面切换到夜间模式(背景变成黑色)
再次点击恢复日间模式(背景变成白色)
<style>
.light {
background-color: #fff;
color: #000;
}
.dark {
background-color: #000;
color: #fff;
}
</style>
<div class="light" style="height:500px">hello,关灯与开灯</div>
<button>关灯</button>
<script>
let div = document.querySelector('div');
let button = document.querySelector('button');
button.onclick = function() {
if (div.className == 'light') {
div.className = 'dark';
button.innerHTML = '开灯';
} else if (div.className == 'dark') {
div.className = 'light';
button.innerHTML = '关灯';
}
}
</script>
操作节点
新增节点
1:创建新节点
createTextNode 创建文本节点
createComment 创建注释节点
createAttribute 创建属性节点
createElement 创建元素节点
2:把节点挂在 dom 树上
使用 appendChild 将节点插入到指定节点的最后一个孩子之后
使用insertBefore将节点插入到指定节点之前
<div class="container">
</div>
<script>
var div = document.createElement('div');
div.id = 'mydiv';
div.className = 'box';
div.innerHTML = 'hehe';
var container = document.querySelector('.container');
container.appendChild(div);
</script>
使用 insertBefore 将节点插入到指定节点之前
var insertedNode = parentNode.insertBefore(newNode, referenceNode);
insertedNode 被插入节点(newNode)
parentNode 新插入节点的父节点
newNode 用于插入的节点
referenceNode newNode 将要插在这个节点之前
如果 referenceNode 为 null 则 newNode 将被插入到子节点的末尾
如果针对一个节点插入两次, 则只有最后一次生效(相当于把元素移动了
<div class="container">
<div>11</div>
<div>22</div>
<div>33</div>
<div>44</div>
</div>
<script>
var newDiv = document.createElement('div');
newDiv.innerHTML = '我是新的节点';
var container = document.querySelector('.container');
console.log(container.children);
// 此处的 children 里有 4 个元素
container.insertBefore(newDiv, container.children[0]);
// 此处的 children 里有 5 个元素(上面新插了一个), 0 号元素是 新节点,
// 1 号元素是 11, 2号节点是 22, 所以是插入到 22 之前.
container.insertBefore(newDiv, container.children[2]);
</script>
一旦一个节点插入完毕, 再针对刚刚的节点对象进行修改, 能够同步影响到 DOM 树中的内容
<div class="container">
<div>11</div>
<div>22</div>
<div>33</div>
<div>44</div>
</div>
<script>
var newDiv = document.createElement('div');
newDiv.innerHTML = '我是新的节点';
var container = document.querySelector('.container');
console.log(container.children);
container.insertBefore(newDiv, container.children[0]);
// 插入完毕后再次修改 newDiv 的内容
newDiv.innerHTML = '我是新节点2';
</script>
删除节点
使用 removeChild 删除子节点
oldChild = element.removeChild(child);
child 为待删除节点
element 为 child 的父节点
返回值为该被删除节点
被删除节点只是从 dom 树被删除了, 但是仍然在内存中, 可以随时加入到 dom 树的其他位置.
如果上例中的 child节点 不是 element 节点的子节点,则该方法会抛出异常
<div class="container">
<div class="child">11</div>
<div class="child">22</div>
<div class="child">33</div>
<div class="child">44</div>
</div>
<script>
var container = document.querySelector('.container');
var childs = document.querySelectorAll('.child');
container.removeChild(childs[2]);
</script>
示例
猜数字游戏
<style>
*{
margin: 0;
padding: 0;
text-align: center;
}
body {
background-image: url(wallhaven-e71ddk.png);
background-size: 100%;
}
</style>
<button id="resetBtn">重新开始一局游戏</button><br>
<span style="color: deeppink;">要猜的数字: </span>
<input type="text">
<button id="guessBtn" style="color: deeppink;">猜</button><br>
<span style="color: deeppink;">结果: </span><span id="result"></span><br>
<span style="color: deeppink;">已经猜的次数: </span><span id="guessCount" style="color: deeppink;">0</span>
<script>
// 1. 先把上面需要用到的元素都拿到.
let resetBtn = document.querySelector('#resetBtn');
let input = document.querySelector('input');
let guessBtn = document.querySelector('#guessBtn');
let resultSpan = document.querySelector('#result');
let guessCountSpan = document.querySelector('#guessCount');
// 2. 生成一个 1-100 的随机整数.
let toGuess = Math.floor(Math.random() * 100) + 1;
console.log(toGuess);
// 3. 实现点击 猜 按钮的逻辑.
guessBtn.onclick = function() {
// 1. 读取到 input 中输入的内容, 并转成整数.
if (input.value == '') {
return;
}
let curNum = parseInt(input.value);
// 2. 判定大小关系, 并给出提示.
if (curNum < toGuess) {
resultSpan.innerHTML = '低了'
resultSpan.style.color = 'red';
} else if (curNum > toGuess) {
resultSpan.innerHTML = '高了';
resultSpan.style.color = 'red';
} else {
resultSpan.innerHTML = '猜对了!';
resultSpan.style.color = 'green';
}
// 3. 更新猜的次数.
let guessCount = parseInt(guessCountSpan.innerHTML);
guessCountSpan.innerHTML = guessCount + 1;
}
// 4. 实现 reset 操作的逻辑(开始新游戏)
resetBtn.onclick = function() {
// 让页面刷新即可~
// location 是和 document 并列关系的对象.
// location 用来控制页面的链接/地址. 通过 reload 操作就可以刷新页面.
location.reload();
}
</script>
表白墙
<body>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body{
background-image: url(wallhaven-1kmk39.jpg);
background-size: 2000px;
}
.container {
width: 100%;
}
h3 {
text-align: center;
padding: 30px 0;
font-size: 24px;
}
p {
text-align: center;
color: rgb(62, 54, 54);
padding: 10px 0;
}
.row {
width: 400px;
height: 50px;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: center;
}
.row span {
width: 60px;
font-size: 20px;
}
.row input {
width: 300px;
height: 40px;
line-height: 40px;
font-size: 20px;
text-indent: 0.5em;
/* 去掉输入框的轮廓线 */
outline: none;
}
.row #submit {
width: 300px;
height: 40px;
font-size: 20px;
line-height: 40px;
margin: 0 auto;
color: white;
background-color: rgb(203, 66, 157);
/* 去掉边框 */
border: none;
border-radius: 10px;
}
.row #submit:active {
background-color: gray;
}
</style>
<div class="container">
<h3>表白墙</h3>
<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>
<script>
// 当用户点击 submit, 就会获取到 input 中的内容, 从而把内容构造成一个 div, 插入到页面末尾.
let submitBtn = document.querySelector('#submit');
submitBtn.onclick = function() {
// 1. 获取到 3 个 input 中的内容.
let inputs = document.querySelectorAll('input');
let from = inputs[0].value;
let to = inputs[1].value;
let msg = inputs[2].value;
if (from == '' || to == '' || msg == '') {
// 用户还没填写完, 暂时先不提交数据.
return;
}
// 2. 生成一个新的 div, 内容就是 input 里的内容. 把这个新的 div 加到页面中.
let div = document.createElement('div');
div.innerHTML = from + ' 对 ' + to + ' 说: ' + msg;
div.className = 'row';
let container = document.querySelector('.container');
container.appendChild(div);
// 3. 清空之前输入框的内容.
for (let i = 0; i < inputs.length; i++) {
inputs[i].value = '';
}
}
</script>
</body>