目录
1.DOM事件基础
1.1 事件监听
1.2 事件监听案例
1.2.1 京东点击关闭顶部广告
1.2.2 随机点名案例
1.3 事件监听版本
2. 事件类型
2.1 事件类型案例
2.1.1 轮播图点击切换
2.1.2 评论字数统计
3.事件对象
3.1 获取事件对象
3.2 事件对象常用属性
3.3 事件对象案例
4.环境对象
5. 回调函数
6.综合案例
1.DOM事件基础
1.1 事件监听
目标:能够给 DOM元素添加事件监听
什么是事件?
事件是在编程时系统内发生的
动作
或者发生的事情 ,比如用户在网页上
单击
一个按钮
什么是事件监听?
就是让程序检测是否有事件产生,一旦有事件触发,就立即调用一个函数做出响应,也称为 绑定事件或者注册事件 ,比如鼠标经过显示下拉菜单,比如点击可以播放轮播图等等。
语法:
事件监听三要素:
- Ø 事件源: 那个dom元素被事件触发了,要获取dom元素对象
- Ø 事件类型: 用什么方式触发,比如鼠标单击 click、鼠标经过 mouseover 等
- Ø 事件调用的函数: 要做什么事
举例说明:
1.2 事件监听案例
1.2.1 京东点击关闭顶部广告
需求:点击关闭之后,顶部关闭
分析:
①:点击的是关闭按钮
②:关闭的是父盒子
核心:利用样式的显示和隐藏完成, display:none 隐藏元素 display:block 显示元素
代码:
李伟兴 09:31:13
<!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>
.box {
position: relative;
width: 1000px;
height: 200px;
background-color: pink;
margin: 100px auto;
text-align: center;
font-size: 50px;
line-height: 200px;
font-weight: 700;
}
.box1 {
position: absolute;
right: 20px;
top: 10px;
width: 20px;
height: 20px;
background-color: skyblue;
text-align: center;
line-height: 20px;
font-size: 16px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="box">
我是广告
<div class="box1">X</div>
</div>
<script>
// 1. 获取事件源
const box1 = document.querySelector('.box1')
// 关闭的是大盒子
const box = document.querySelector('.box')
// 2. 事件侦听
box1.addEventListener('click', function () {
box.style.display = 'none'
})
</script>
</body>
</html>
1.2.2 随机点名案例
业务分析:
① 点击开始按钮随机抽取数组的一个数据,放到页面中
② 点击结束按钮删除数组当前抽取的一个数据
③ 当抽取到最后一个数据的时候,两个按钮同时禁用(写点开始里面,只剩最后一个数据不用抽了)
核心:利用定时器快速展示,停止定时器结束展示
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
h2 {
text-align: center;
}
.box {
width: 600px;
margin: 50px auto;
display: flex;
font-size: 25px;
line-height: 40px;
}
.qs {
width: 450px;
height: 40px;
color: red;
}
.btns {
text-align: center;
}
.btns button {
width: 120px;
height: 35px;
margin: 0 50px;
}
</style>
</head>
<body>
<h2>随机点名</h2>
<div class="box">
<span>名字是:</span>
<div class="qs">这里显示姓名</div>
</div>
<div class="btns">
<button class="start">开始</button>
<button class="end">结束</button>
</div>
<script>
// 数组
const arr = ['马超', '黄忠', '赵云', '关羽', '张飞']
// 定时器的全局变量
let time = 0
// 数组随机下标的全局变量
let random = 0
// 获取开始按钮事件
const start = document.querySelector('.start')
// 获取结束按钮事件
const end = document.querySelector('.end')
// 开始事件函数
start.addEventListener('click', function () {
//开启定时器
time = setInterval(function () {
// 开始事件处理
const qs = document.querySelector('.qs')
random = parseInt(Math.random() * arr.length)
qs.innerHTML = arr[random]
}, 50)
if (arr.length === 1) {
start.disabled = true
end.disabled = true
}
})
// 结束事件函数
end.addEventListener('click', function () {
// 关闭定时器
clearInterval(time)
// 删除元素
arr.splice(random, 1)
console.log(arr)
})
</script>
</body>
</html>
1.3 事件监听版本
DOM L0 :事件源.on事件 = function() { }
DOM L2 :事件源.addEventListener(事件, 事件处理函数)
两者区别:
- on方式会被覆盖相同的事件(比如alert),addEventListener方式可绑定多次,拥有事件更多特性,推荐使用
2.事件类型
2.1 事件类型案例
2.1.1 轮播图点击切换
需求:当点击左右的按钮,可以切换轮播图
分析:
①:右侧按钮点击,变量++,如果大于等于8,则复原0
②:左侧按钮点击,变量--,如果小于0,则复原最后一张
③:鼠标经过暂停定时器
④:鼠标离开开启定时器
⑤: 鼠标经过和鼠标离开触发事件
效果:
20240804_182140
代码:
<!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>
* {
box-sizing: border-box;
}
.slider {
width: 560px;
height: 400px;
overflow: hidden;
}
.slider-wrapper {
width: 100%;
height: 320px;
}
.slider-wrapper img {
width: 100%;
height: 100%;
display: block;
}
.slider-footer {
height: 80px;
background-color: rgb(100, 67, 68);
padding: 12px 12px 0 12px;
position: relative;
}
.slider-footer .toggle {
position: absolute;
right: 0;
top: 12px;
display: flex;
}
.slider-footer .toggle button {
margin-right: 12px;
width: 28px;
height: 28px;
appearance: none;
border: none;
background: rgba(255, 255, 255, 0.1);
color: #fff;
border-radius: 4px;
cursor: pointer;
}
.slider-footer .toggle button:hover {
background: rgba(255, 255, 255, 0.2);
}
.slider-footer p {
margin: 0;
color: #fff;
font-size: 18px;
margin-bottom: 10px;
}
.slider-indicator {
margin: 0;
padding: 0;
list-style: none;
display: flex;
align-items: center;
}
.slider-indicator li {
width: 8px;
height: 8px;
margin: 4px;
border-radius: 50%;
background: #fff;
opacity: 0.4;
cursor: pointer;
}
.slider-indicator li.active {
width: 12px;
height: 12px;
opacity: 1;
}
</style>
</head>
<body>
<div class="slider">
<div class="slider-wrapper">
<img src="./images/slider01.jpg" alt="" />
</div>
<div class="slider-footer">
<p>对人类来说会不会太超前了?</p>
<ul class="slider-indicator">
<li class="active"></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
<div class="toggle">
<button class="prev"><</button>
<button class="next">></button>
</div>
</div>
</div>
<script>
// 1. 初始数据
const data = [
{ url: './images/slider01.jpg', title: '对人类来说会不会太超前了?', color: 'rgb(100, 67, 68)' },
{ url: './images/slider02.jpg', title: '开启剑与雪的黑暗传说!', color: 'rgb(43, 35, 26)' },
{ url: './images/slider03.jpg', title: '真正的jo厨出现了!', color: 'rgb(36, 31, 33)' },
{ url: './images/slider04.jpg', title: '李玉刚:让世界通过B站看到东方大国文化', color: 'rgb(139, 98, 66)' },
{ url: './images/slider05.jpg', title: '快来分享你的寒假日常吧~', color: 'rgb(67, 90, 92)' },
{ url: './images/slider06.jpg', title: '哔哩哔哩小年YEAH', color: 'rgb(166, 131, 143)' },
{ url: './images/slider07.jpg', title: '一站式解决你的电脑配置问题!!!', color: 'rgb(53, 29, 25)' },
{ url: './images/slider08.jpg', title: '谁不想和小猫咪贴贴呢!', color: 'rgb(99, 72, 114)' },
]
//设置变量
let i = 0
//2.获取数组对象
const img = document.querySelector('.slider-wrapper img')
const p = document.querySelector('.slider-footer p')
const col = document.querySelector('.slider-footer')
//3.点击鼠标next按钮事件
const next = document.querySelector('.next')
next.addEventListener('click', function () {
//自增
i++
//重刚开始播放
if (i >= data.length) {
i = 0
}
//页面渲染函数
toggle()
})
//4.点击鼠标prev按钮事件
const prev = document.querySelector('.prev')
prev.addEventListener('click', function () {
//自减
i--
//重最后一个往前播放
if (i < 0) {
i = data.length - 1
}
//页面渲染函数
toggle()
})
//5.自动播放
let spread = setInterval(function () {
//调用js内部函数实现自动播放
next.click()
}, 1000)
//6.鼠标在大盒子里面(停止自动播放)
const box = document.querySelector('.slider')
box.addEventListener('mouseenter', function () {
//停止定时器
clearInterval(spread)
})
//7.鼠标在大盒子外面(自动播放)
box.addEventListener('mouseleave', function () {
//先停止定时器
clearInterval(spread)
//再开启定时器
spread = setInterval(function () {
//调用js内部函数实现自动播放
next.click()
}, 1000)
})
//自定义函数(抽取重复的代码块)
function toggle() {
//获取到的对象取值
img.src = data[i].url
p.innerHTML = data[i].title
col.style.backgroundColor = data[i].color
//让白点随着移动(先移除,再添加)
document.querySelector('.slider-indicator .active').classList.remove('active')
document.querySelector(`.slider-indicator li:nth-child(${i + 1})`).classList.add('active')
}
</script>
</body>
</html>
2.1.2 评论字数统计
需求:用户输入文字,可以计算用户输入的字数。
分析:
①:判断用输入事件 input
②:不断取得文本框里面的字符长度, 文本域.value.length
③:把获得数字给下面文本框
效果:
代码:
<!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>
.wrapper {
min-width: 400px;
max-width: 800px;
display: flex;
justify-content: flex-end;
}
.avatar {
width: 48px;
height: 48px;
border-radius: 50%;
overflow: hidden;
background: url(./images/avatar.jpg) no-repeat center / cover;
margin-right: 20px;
}
.wrapper textarea {
outline: none;
border-color: transparent;
resize: none;
background: #f5f5f5;
border-radius: 4px;
flex: 1;
padding: 10px;
transition: all 0.5s;
height: 30px;
}
.wrapper textarea:focus {
border-color: #e4e4e4;
background: #fff;
height: 50px;
}
.wrapper button {
background: #00aeec;
color: #fff;
border: none;
border-radius: 4px;
margin-left: 10px;
width: 70px;
cursor: pointer;
}
.wrapper .total {
margin-right: 80px;
color: #999;
margin-top: 5px;
opacity: 0;
transition: all 0.5s;
}
.list {
min-width: 400px;
max-width: 800px;
display: flex;
}
.list .item {
width: 100%;
display: flex;
}
.list .item .info {
flex: 1;
border-bottom: 1px dashed #e4e4e4;
padding-bottom: 10px;
}
.list .item p {
margin: 0;
}
.list .item .name {
color: #FB7299;
font-size: 14px;
font-weight: bold;
}
.list .item .text {
color: #333;
padding: 10px 0;
}
.list .item .time {
color: #999;
font-size: 12px;
}
</style>
</head>
<body>
<div class="wrapper">
<i class="avatar"></i>
<textarea id="tx" placeholder="发一条友善的评论" rows="2" maxlength="200"></textarea>
<button>发布</button>
</div>
<div class="wrapper">
<span class="total">0/200字</span>
</div>
<div class="list">
<div class="item" style="display: none;">
<i class="avatar"></i>
<div class="info">
<p class="name">清风徐来</p>
<p class="text">大家都辛苦啦,感谢各位大大的努力,能圆满完成真是太好了[笑哭][支持]</p>
<p class="time">2022-10-10 20:29:21</p>
</div>
</div>
</div>
<script>
//获取文本域对象
const tx = document.querySelector('#tx')
//获取评论字数对象
const total = document.querySelector('.total')
/* 触发事件 */
//当鼠标焦聚在表单,就让opacity变成不透明就可以看到评论数子
tx.addEventListener('focus', function () {
total.style.opacity = 1
})
//当鼠标失去焦聚在表单,就让opacity变成透明就看不到评论数子
tx.addEventListener('blur', function () {
total.style.opacity = 0
})
//获取表单输入字数,写到评论字数的对象中
tx.addEventListener('input', function () {
total.innerHTML = `${tx.value.length}/200字`
})
</script>
</body>
</html>
3.事件对象
3.1 获取事件对象
事件对象是什么?
- Ø 也是个对象,这个对象里有事件触发时的相关信息
- Ø 例如:鼠标点击事件中,事件对象就存了鼠标点在哪个位置等信息
使用场景:
- Ø 可以判断用户按下哪个键,比如按下回车键可以发布新闻
- Ø 可以判断鼠标点击了哪个元素,从而做相应的操作
下图,只有我鼠标按下删除键,才会删除该信息
语法:
- Ø 在事件绑定的回调函数的第一个参数就是事件对象
- Ø 一般命名为event、ev、e
3.2 事件对象常用属性
目标:能够使用常见事件对象属性
部分常用属性:
Ø
type
- p 获取当前的事件类型
Ø
clientX/clientY
- p 获取光标相对于浏览器可见窗口左上角的位置
Ø
offsetX/offsetY
- p 获取光标相对于当前DOM元素左上角的位置
Ø
key
- p 用户按下的键盘键的值
- p 现在不提倡使用keyCode
3.3 事件对象案例
评论回车发布
需求:按下回车键盘,可以发布信息
分析:
①:用到按下键盘事件 keydown 或者 keyup 都可以
②:如果用户按下的是回车键盘,则发布信息
③:让留言信息模块显示
,
把拿到的数据渲染到对应标签内部
代码:
<!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>
.wrapper {
min-width: 400px;
max-width: 800px;
display: flex;
justify-content: flex-end;
}
.avatar {
width: 48px;
height: 48px;
border-radius: 50%;
overflow: hidden;
background: url(./images/avatar.jpg) no-repeat center / cover;
margin-right: 20px;
}
.wrapper textarea {
outline: none;
border-color: transparent;
resize: none;
background: #f5f5f5;
border-radius: 4px;
flex: 1;
padding: 10px;
transition: all 0.5s;
height: 30px;
}
.wrapper textarea:focus {
border-color: #e4e4e4;
background: #fff;
height: 50px;
}
.wrapper button {
background: #00aeec;
color: #fff;
border: none;
border-radius: 4px;
margin-left: 10px;
width: 70px;
cursor: pointer;
}
.wrapper .total {
margin-right: 80px;
color: #999;
margin-top: 5px;
opacity: 0;
transition: all 0.5s;
}
.list {
min-width: 400px;
max-width: 800px;
display: flex;
}
.list .item {
width: 100%;
display: flex;
}
.list .item .info {
flex: 1;
border-bottom: 1px dashed #e4e4e4;
padding-bottom: 10px;
}
.list .item p {
margin: 0;
}
.list .item .name {
color: #FB7299;
font-size: 14px;
font-weight: bold;
}
.list .item .text {
color: #333;
padding: 10px 0;
}
.list .item .time {
color: #999;
font-size: 12px;
}
</style>
</head>
<body>
<div class="wrapper">
<i class="avatar"></i>
<textarea id="tx" placeholder="发一条友善的评论" rows="2" maxlength="200"></textarea>
<button>发布</button>
</div>
<div class="wrapper">
<span class="total">0/200字</span>
</div>
<div class="list">
<div class="item" style="display: none;">
<i class="avatar"></i>
<div class="info">
<p class="name">清风徐来</p>
<p class="text">大家都辛苦啦,感谢各位大大的努力,能圆满完成真是太好了[笑哭][支持]</p>
<p class="time">2022-10-10 20:29:21</p>
</div>
</div>
</div>
<script>
//获取文本域对象
const tx = document.querySelector('#tx')
//获取评论字数对象
const total = document.querySelector('.total')
//获取评论留言对象
const text = document.querySelector('.text')
//获取盒子对象
const item = document.querySelector('.item')
/* 触发事件 */
//当鼠标焦聚在表单,就让opacity变成不透明就可以看到评论数子
tx.addEventListener('focus', function () {
total.style.opacity = 1
})
//当鼠标失去焦聚在表单,就让opacity变成透明就看不到评论数子
tx.addEventListener('blur', function () {
total.style.opacity = 0
})
//获取表单输入字数,写到评论字数的对象中
tx.addEventListener('input', function () {
total.innerHTML = `${tx.value.length}/200字`
})
//按下回车键就发布评论
tx.addEventListener('keyup', function (e) {
if (e.key === 'Enter') {
if (tx.value.trim()) {
//把表单的评论写入对象
text.innerHTML = `${tx.value}`
//显示评论留言
item.style.display = 'block'
}
//按完回车键后,清空表单的数据
tx.value = ''
//清空表单显示的字数
total.innerHTML = '0/200字'
}
})
</script>
</body>
</html>
4.环境对象
目标:能够分析判断函数运行在不同环境中 this 所指代的对象
环境对象:
指的是函数内部特殊的
变量 this
,它代表着当前函数运行时所处的环境
作用:
弄清楚this的指向,可以让我们代码更简洁
- Ø 函数的调用方式不同,this 指代的对象也不同
- Ø 【谁调用, this 就是谁】 是判断 this 指向的粗略规则
- Ø 直接调用函数,其实相当于是 window.函数,所以 this 指代 window
5.回调函数
目标:能够说出什么是回调函数
如果将函数 A 做为参数传递给函数 B 时,我们称函数 A 为
回调函数
简单理解: 当一个函数当做参数来传递给另外一个函数的时候,这个函数就是
回调函数
常见的使用场景:
6.综合案例
Tab栏切换
需求:鼠标经过不同的选项卡,底部可以显示 不同的内容
分析:
- ①:主要核心是类的切换, 设定一个当前类,可以让当前元素高亮
- ②:鼠标经过当前选项卡,先移除其余元素身上的当前类,而只给当前元素添加类,
- ③:注意,当前类只能有一个
演示:
代码:
<!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>tab栏切换</title>
<style>
* {
margin: 0;
padding: 0;
}
.tab {
width: 590px;
height: 340px;
margin: 20px;
border: 1px solid #e4e4e4;
}
.tab-nav {
width: 100%;
height: 60px;
line-height: 60px;
display: flex;
justify-content: space-between;
}
.tab-nav h3 {
font-size: 24px;
font-weight: normal;
margin-left: 20px;
}
.tab-nav ul {
list-style: none;
display: flex;
justify-content: flex-end;
}
.tab-nav ul li {
margin: 0 20px;
font-size: 14px;
}
.tab-nav ul li a {
text-decoration: none;
border-bottom: 2px solid transparent;
color: #333;
}
.tab-nav ul li a.active {
border-color: #e1251b;
color: #e1251b;
}
.tab-content {
padding: 0 16px;
}
.tab-content .item {
display: none;
}
.tab-content .item.active {
display: block;
}
</style>
</head>
<body>
<div class="tab">
<div class="tab-nav">
<h3>每日特价</h3>
<ul>
<li><a class="active" href="javascript:;">精选</a></li>
<li><a href="javascript:;">美食</a></li>
<li><a href="javascript:;">百货</a></li>
<li><a href="javascript:;">个护</a></li>
<li><a href="javascript:;">预告</a></li>
</ul>
</div>
<div class="tab-content">
<div class="item active"><img src="./images/tab00.png" alt="" /></div>
<div class="item"><img src="./images/tab01.png" alt="" /></div>
<div class="item"><img src="./images/tab02.png" alt="" /></div>
<div class="item"><img src="./images/tab03.png" alt="" /></div>
<div class="item"><img src="./images/tab04.png" alt="" /></div>
</div>
</div>
<script>
const as = document.querySelectorAll('.tab-nav a')
for (let i = 0; i < as.length; i++) {
//当鼠标经过标签就触发事件
as[i].addEventListener('mouseenter', function () {
//排他思想(先移除,在添加)
document.querySelector('.tab-nav .active').classList.remove('active')
//添加当前鼠标经过的标签
this.classList.add('active')
//当鼠标经过该标签之后,显示对应的隐形大盒子
//排他思想(先移除,在添加)
document.querySelector('.tab-content .active').classList.remove('active')
// 对应序号的那个 item 显示 添加 active 类
document.querySelector(`.tab-content .item:nth-child(${i + 1})`).classList.add('active')
})
}
</script>
</body>
</html>