webAPI
一、事件流
1.事件流指的是事件完整执行过程中的流动路径
2.说明:完整执行过程中的流动路径会经历两个阶段,分别是捕获阶段、冒泡阶段
(捕获阶段是 从父到子 冒泡阶段是从子到父)
3.事件冒泡
①当一个元素的事件被触发时,同样的事件将会在该元素的所有祖先元素中依次被触发。这一过程被称为事件冒泡
②简单理解:当一个元素触发事件后,会依次向上调用所有父级元素的同名事件
4.事件捕获
①从DOM的根元素开始去执行对应的事件 (从外到里)
②语法
DOM.addEventListener(事件类型,事件处理函数,是否使用捕获机制)
// addEventListener第三个参数传入true代表是捕获阶段触发(很少使用)
// 若传入false代表冒泡阶段触发,默认就是false
// 若是用 L0 事件监听,则只有冒泡阶段,没有捕获
<body>
<div class="a">
爷
<div class="b">
爸
<div class="c">儿</div>
</div>
</div>
<script>
const a = document.querySelector(".a");
a.addEventListener(
"click",
function () {
console.log("a");
},
true
); // 捕获
const b = document.querySelector(".b");
b.addEventListener(
"click",
function () {
console.log("b");
},
true
); // 捕获
const c = document.querySelector(".c");
c.addEventListener(
"click",
function () {
console.log("c");
},
false
); // 冒泡———>默认
</script>
</body>
5.事件流总结
(1)给多个父子结构的标签绑定事件, 先点击了子元素, 产生事件流动
(2)事件流动 分成了两个阶段
(3)捕获阶段 父节点 流动到 子节点
(4)我们可以修改触发事件 让它选择使用 捕获阶段还是冒泡阶段(默认)
addEventListener 可以选择使用冒泡还是捕获
addEventListener(事件类型,事件处理函数,捕获还是冒泡(默认值 false,可以省略))
addEventListener("click",function(){}, true )
(5)总结
①捕获和冒泡特点 :捕获阶段是 从父到子 冒泡阶段是从子到父
②默认情况 冒泡 如果想要修改 可以 addEventListener 第三个参数 传入 true即可
③以后的代码开发过程中,还是继续使用默认的 冒泡阶段
6.阻止冒泡事件
(1)关键阻止冒泡代码
// 阻止事件冒泡
event.stopPropagation();
(2)原理理解:当点击子元素时,捕获事件从父元素开始到子元素,因此首先展现的属性为父元素属性(如:给子元素添加阻止冒泡的代码时,将阻止父元素冒泡)
<script>
const p = document.querySelector("p");
const a = document.querySelector(".a");
a.addEventListener("click", function () {
p.style.backgroundColor = "red";
p.innerText = +p.innerText + 1;
console.log("a");
});
const b = document.querySelector(".b");
b.addEventListener("click", function (event) {
console.log("b");
p.innerText = +p.innerText + 10;
p.style.backgroundColor = "blue";
// 阻止事件冒泡
event.stopPropagation();
});
const c = document.querySelector(".c");
c.addEventListener("click", function (event) {
console.log("c");
p.innerText = +p.innerText + 100;
p.style.backgroundColor = "green";
// 阻止事件冒泡
event.stopPropagation();
});
const d = document.querySelector(".d");
d.addEventListener("click", function (event) {
console.log("d");
p.innerText = +p.innerText + 100;
p.style.backgroundColor = "pink";
// 阻止事件冒泡
event.stopPropagation();
});
/*
引出新的知识 阻止冒泡! 下一节课 优雅的方式来解决刚才的问题!
在事件对象中 event 找到一个方法 停止冒泡 event.stopPropagation();
*/
</script>
7.阻止标签默认行为
(1)a标签的点击跳转
(2)form表单中button点击刷新行为
①阻止默认行为 - form表单 有一个 submit 事件 理解提交表单的触发-点击按钮的时候触发
② 给button按钮绑定点击事件 也去阻止试试
③给button按钮 添加一个 type="button" 属性
④换成 input标签 type="button"
⑤把button 移出form表单的区域
⑥使用新技术 阻止标签默认行为
(3)关键代码展示
// 阻止默认行为代码
// event.preventDefault();
// 补充添加刷新功能 form标签,原理:去除默认属性,添加新功能-刷新
<form>
<!-- <button type="button">点击我 就会自动刷新</button> -->
<!-- <input type="button" value="点击我"> -->
<button>刷新</button>
</form>
<body>
<a href="http://www.baidu.com">百度</a>
<form>
<!-- <button type="button">点击我 就会自动刷新</button> -->
<!-- <input type="button" value="点击我"> -->
<button>刷新</button>
</form>
<script>
const a = document.querySelector("a");
const form = document.querySelector("form");
const button = document.querySelector("button");
a.addEventListener("click", function (event) {
console.log("a标签的点击触发啦");
// 阻止a标签的默认行为,让他不要跳转
event.preventDefault();
});
// form.addEventListener("submit",function (event) {
// // 不要让页面再刷新
// event.preventDefault();
// })
// button.addEventListener("click",function (event) {
// event.preventDefault(); // 不要让页面再刷新
// })
</script>
</body>
8.阻止默认行为案例---鼠标右键
(1)思路
①写死标签样式(隐藏ul列表)
② js部分
注册事件(跟随鼠标移动 获取 左边、 重新显现ul列表)
绑定事件类型
功能内容:点击右键 出现选项列表(取消默认功能、注册点击事件---重新隐藏列表)
(2)代码
js关键代码
// 事件类型 鼠标右键contextmenu 触发
document.body.addEventListener("contextmenu",function(){})
// 阻止鼠标右键原有的默认功能/行为
event.preventDefault();
html部分添加的骨架代码
<ul class="menu">
<li>打开</li>
<li>查看</li>
<li>属性</li>
<li>返回桌面</li>
</ul>
css部分代码
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
height: 100vh;
}
.menu {
list-style: none;
padding: 10px;
border-radius: 5px;
border: 1px solid #ccc;
width: 150px;
/* 绝对定位 通过js获取鼠标定位 赋值left 和 top
使标签能够与跟随鼠标移动
*/
position: fixed;
/* 隐藏标签 点击鼠标右键后 显现实现对应功能*/
display: none;
}
li {
height: 40px;
display: flex;
align-items: center;
padding-left: 10px;
border-bottom: 1px solid #ccc;
}
li:hover {
background-color: skyblue;
color: #fff;
cursor: pointer;
}
li:last-child {
border-bottom: none;
}
</style>
js部分代码
<script>
//注册事件
const menu = document.querySelector(".menu");
// contextmenu 鼠标右键 绑定事件类型
document.body.addEventListener("contextmenu", function (event) {
event.preventDefault();
// 鼠标位置 clientX/clientY
const left = event.clientX;
const top = event.clientY;
menu.style.display = "block";
menu.style.left = left + "px";
menu.style.top = top + "px";
// 绑定点击 body标签时,ul列表隐藏
document.body.addEventListener("click", function () {
menu.style.display = "none";
});
});
</script>
二、事件委托
1.事件委托是利用事件流的特征解决一些开发需求的知识技巧
2.总结: ①优点:给父级元素加事件(可以提高性能) ②原理:事件委托其实是利用事件冒泡的特点, 给父元素添加事件,子元素可以触发 ③实现:事件对象.target 可以获得真正触发事件的元素
<script>
const ul = document.querySelector("ul");
ul.addEventListener("click", function (event) {
if (event.target.nodeName === "LI") {
// event.target.nodeName 获取标签名
// event.target.style.backgroundColor="red";
// console.log(event.target);
// 只有点击了li标签才触发
// console.log(event.target.nodeName);// 当前点击的元素的标签名 大写
event.target.style.backgroundColor = "red";
}
});
</script>
3.学生信息列表案例
(1)
①定义数组 负责存放表格要显示的数据
②根据数组渲染页面
(2)按钮绑定点击事件
①创建一个新的对象 把表单数据都合并到对象中
②给数组插入新的元素
③数组发生改变 重新调用渲染页面的函数
④表单数据清空
(3)tbody绑定点击事件,同时判断被点击的是不是 del 删除标签
①判断当前点击的是不是a标签
②获取到a标签 上存放的 index
③执行数组删除元素
④调用根据数组渲染页面的函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>08-综合案例-模版</title>
<style>
* {
margin: 0;
padding: 0;
}
a {
text-decoration: none;
color: #721c24;
}
h1 {
text-align: center;
color: #333;
margin: 20px 0;
}
table {
margin: 0 auto;
width: 800px;
border-collapse: collapse;
color: #004085;
}
th {
padding: 10px;
background: #cfe5ff;
font-size: 20px;
font-weight: 400;
}
td,
th {
border: 1px solid #b8daff;
}
td {
padding: 10px;
color: #666;
text-align: center;
font-size: 16px;
}
tbody tr {
background: #fff;
}
tbody tr:hover {
background: #e1ecf8;
}
.info {
width: 900px;
margin: 50px auto;
text-align: center;
}
.info input {
width: 80px;
height: 25px;
outline: none;
border-radius: 5px;
border: 1px solid #b8daff;
padding-left: 5px;
}
.info button {
width: 60px;
height: 25px;
background-color: #004085;
outline: none;
border: 0;
color: #fff;
cursor: pointer;
border-radius: 5px;
}
.info .age {
width: 50px;
}
</style>
</head>
<body>
<h1>新增学员</h1>
<div class="info">
姓名:<input type="text" class="uname" /> 年龄:<input
type="text"
class="age"
/>
性别:
<select name="gender" id="" class="gender">
<option value="男">男</option>
<option value="女">女</option>
</select>
薪资:<input type="text" class="salary" /> 就业城市:<select
name="city"
id=""
class="city"
>
<option value="北京">北京</option>
<option value="上海">上海</option>
<option value="广州">广州</option>
<option value="深圳">深圳</option>
<option value="曹县">曹县</option>
</select>
<button class="add">录入</button>
</div>
<h1>就业榜</h1>
<table>
<thead>
<tr>
<th>学号</th>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>薪资</th>
<th>就业城市</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<!-- <tr>
<td>1</td>
<td>这是名称</td>
<td>这是年龄</td>
<td>这是性别</td>
<td>这是工资</td>
<td>这是所在城市</td>
<td>
<a href="javascript:" class="del">删除</a>
</td>
</tr> -->
</tbody>
</table>
<script>
// 1.1 定义数组 负责存放表格要显示的数据
let arr = [];
const tbody = document.querySelector("tbody");
// 2 给 录入绑定点击事件
const add = document.querySelector(".add");
const uname = document.querySelector(".uname");
const age = document.querySelector(".age");
const gender = document.querySelector(".gender");
const salary = document.querySelector(".salary");
const city = document.querySelector(".city");
// 1.2 根据数组渲染页面
renderTableByArr();
// 2 按钮绑定点击事件
add.addEventListener("click", function () {
// 2.1 创建一个新的对象 把表单数据都合并到对象中
const data = {
// 学号
id: Date.now(),
// 姓名
uname: uname.value,
// 年龄
age: age.value,
// 性别
gender: gender.value,
// 薪资
salary: salary.value,
// 就业城市
city: city.value,
};
// 老师打了一个 断点 来验证 上面的代码 没有写错
// 2.2 给数组插入新的元素
arr.push(data);
// 2.3 数组发生改变 重新调用渲染页面的函数
renderTableByArr();
// 2.4 表单数据清空
uname.value = "";
age.value = "";
gender.value = "男";
salary.value = "";
city.value = "北京";
});
// 3 tbody绑定点击事件,同时判断被点击的是不是 del 删除标签
tbody.addEventListener("click", function (event) {
// 3.1 判断当前点击的是不是a标签
if (event.target.nodeName === "A") {
// <a data-index="2" href="javascript:" class="del">删除</a>
// 获取到a标签 上存放的 index
// event.target = a标签的dom元素
// console.dir(event.target.dataset.index)
const index = event.target.dataset.index;
// 3.3 执行数组删除元素
arr.splice(index, 1);
// 3.4 调用根据数组渲染页面的函数
renderTableByArr();
}
});
// 根据数组渲染表格
function renderTableByArr() {
let html = ``;
for (let index = 0; index < arr.length; index++) {
html += `
<tr>
<td>${arr[index].id}</td>
<td>${arr[index].uname}</td>
<td>${arr[index].age}</td>
<td>${arr[index].gender}</td>
<td>${arr[index].salary}</td>
<td>${arr[index].city}</td>
<td>
<a data-index="${index}" href="javascript:" class="del">删除</a>
</td>
</tr>
`;
}
// 把生成的tr插入到 tbody中
tbody.innerHTML = html;
}
</script>
</body>
</html>
三、scroll滚动事件
1.将滚轮添加给对应元素
window.addEventListener("scroll",function (){})
<script>
// window.addEventListener("scroll",function () {
// console.log("我滚啦 你呢");
// })
const div = document.querySelector("div");
div.addEventListener("scroll", function () {
console.log("div又开始滚啦");
});
const p = document.querySelector("p");
p.addEventListener("scroll", function () {
console.log("p又开始滚啦");
});
</script>
2.获取当前滚轮滚动的距离
<script>
// 页面级别的滚动
let h1_14 = document.querySelector(".h1_14");
window.addEventListener("scroll", function () {
// 这个代码可以获取到当前页面的滚动距离
console.log(document.documentElement.scrollTop);
});
</script>
3.固定导航条案例----效果滚动到一定位置,导航条固定不动
(1)思路:
结构:
<header></header>
<nav></nav>
<div>
<h1>1</h1>
<h1>2</h1>
<h1>3</h1>
...
<h1>100</h1>
</div>
①需要在页面滚动距离 大于或者等于 250 的高时候
②设置nav标签做一个 固定定位
③否则就取消固定定位
④小bug 因为 nav标签做固定定位,不再拥有高度,自然把下面的标签给挡住
⑤给nav上面的标签 header标签 添加下外边距,大小 等于 nav的高
(2)关键代码
// 获取页面滚动的高度
const scrollTop = document.documentElement.scrollTop;
// 判断滚动scrollTop到达多少值时设置固定
if (scrollTop >= 250) {
// 添加固定定位
nav.classList.add("fixed");
// 给头部标签一个下外边距,决绝脱标问题
header.style.marginBottom = 150 + "px";
} else {
nav.classList.remove("fixed");
header.style.marginBottom = 0;
}
(3)CSS实现方式
nav {
background-color: orange;
height: 150px;
/* 粘性定位 兼容性问题 慎用! */
position: sticky;
left: 0;
top: 0;
width: 100%;
四、火箭快速返回案例
1.思路
(1)设置页面的高度 200vh 设置渐变色
(2)先完成静态结构
①定位 右下角 火箭图片
②鼠标移上去 火箭图片切换- 会动的火箭图片
③页面滚动到一定的距离 1500: 让小火箭显示出来, 否则 小火箭就隐藏
(3)代码
①结构代码
<a href="javascript:;"></a>
②CSS代码
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
height: 200vh;
background-image: linear-gradient(black, red, blue, green);
// 背景颜色渐变
/ *background-image: linear-gradient(red, blue); */
}
a {
width: 150px;
height: 195px;
position: fixed;
bottom: 100px;
right: 50px;
background-image: url(./images/gotop.png);
display: none;
}
a:hover {
background-image: url(./images/gotop.gif);
}
</style>
(3)js代码
<script>
/*
步骤:
1 设置页面的高度 200vh 设置渐变色
2 先完成静态结构
1 定位 右下角 火箭图片
2 鼠标移上去 火箭图片切换- 会动的火箭图片
3 页面滚动到一定的距离 1500
让小火箭显示出来
否则 小火箭就隐藏
*/
const a = document.querySelector("a");
const body = document.querySelector("body");
window.addEventListener("scroll", function () {
// 获取页面滚动的距离
const scrollTop = document.documentElement.scrollTop;
if (scrollTop > 700) {
// 显示火箭
a.style.display = "block";
} else {
// 隐藏
a.style.display = "none";
}
});
a.addEventListener("click", function () {
// 定时器 结合 滚轮距离 逐步减小 达到缓慢返回顶部的效果
let timeID = setInterval(function () {
document.documentElement.scrollTop -= 100;
console.log("定时器");
// 清除定时器
if (document.documentElement.scrollTop <= 0) {
clearInterval(timeID);
}
}, 100);
});
</script>