目标:掌握事件绑定处理和事件对象,完成常见网页交互
- 事件监听
- 事件类型
- 事件对象
- 拓展知识
- 综合案例
描述 | 属性/方法 | 效果 |
事件监听 | 元素.addEventListener() | 事件监听,事件绑定,事件注册 |
事件类型 | 鼠标事件 | click 鼠标点击 mouseenter 鼠标进入 mouseleave 鼠标离开 |
焦点事件 | focus 获得焦点 blur 失去焦点 | |
键盘事件 | keydown 键盘按下 keyup 键盘抬起 | |
文本事件 input | 当表单value 被修改时触发 | |
事件对象 | e.key | 判断用户按下哪个键 |
环境对象 | this | 谁调用,指向谁 |
事件监听
监听什么?
以前写的代码都是自动执行的,我们希望一段代码在某个特定的时机才去执行,比如
- 点击按钮可以弹出警示框
- 比如鼠标经过显示下拉菜单等等
像上述功能,需要浏览器时刻监听着用户的行为来做特定的事情(事件),这个就叫做监听
事件
事件是浏览器针对用户的各种行为定义出的一些列的响应机制,当程序在运行时,用户特定的行为就会触发特定的响应机制来执行指定的函数代码
- 比如用户点击按钮时,可以 触发
click
事件,弹出警示框
- 比如用户使用鼠标划入某个盒子时,可以触发
mouseenter
事件,显示下拉菜单
事件监听基本用法
事件监听也称为: 事件注册、事件绑定
语法:
元素对象.addEventListener('事件类型', 事件处理函数)
事件监听三要素
- 事件源(哪个元素对象被触发了) -> 事件监听是将事件处理函数注册到元素对象身上
- 事件类型 (什么情况下触发,点击还是鼠标经过等)
- 事件处理函数(要做什么事情,是弹出警告框,还是修改元素值,还是修改css属性)
<!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>
<button class="btn">唐伯虎</button>
<script>
// 需求: 点击button按钮,页面会弹出一个警示框,内容显示 '秋香'
// 事件监听语法:
// 元素对象.addEventListener('事件类型', 事件处理函数)
// 1. 获取元素对象 button按钮
const btn = document.querySelector('.btn')
// 2. 事件监听
btn.addEventListener('click', function () {
alert('秋香')
})
</script>
</body>
</html>
注意:
1.事件类型要加引号,小写
2.函数是点击之后再去执行,每次点击都会执行一次
事件监听-随堂练习
需求:点击关闭按钮之后,关掉登录提示盒子
分析:
①:事件源: 关闭按钮 a链接
②:事件类型:鼠标点击 click
③:事件处理程序:关闭的是父盒子
核心:利用样式的显示和隐藏完成, display:none 隐藏元素 display:block 显示元素
图片素材下载:📎images.rar
<!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>
.pop {
display: block;
visibility: visible;
position: fixed;
z-index: 9999;
left: 50%;
top: 50%;
width: 530px;
height: 254px;
margin-top: -127px;
margin-left: -265px;
background: url(./images/login.webp) no-repeat;
}
.close {
position: absolute;
right: 0;
top: 0;
width: 40px;
height: 40px;
}
</style>
</head>
<body>
<div class="pop">
<a href="javascript:;" class="close"></a>
</div>
<script>
// 点击关闭按钮可以关闭父盒子
// 确定事件三要素:
// 1. 事件源: a链接
// 2. 事件类型:鼠标点击事件click
// 3. 事件处理函数: 将div.pop盒子关闭
</script>
</body>
</html>
<!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>
.pop {
display: block;
visibility: visible;
position: fixed;
z-index: 9999;
left: 50%;
top: 50%;
width: 530px;
height: 254px;
margin-top: -127px;
margin-left: -265px;
background: url(./images/login.webp) no-repeat;
}
.close {
position: absolute;
right: 0;
top: 0;
width: 40px;
height: 40px;
}
</style>
</head>
<body>
<div class="pop">
<a href="javascript:;" class="close"></a>
</div>
<script>
// 点击关闭按钮可以关闭父盒子
// 确定事件三要素:
// 1. 事件源: a链接
// 2. 事件类型:鼠标点击事件click
// 3. 事件处理函数: 函数体代码为 将.pop盒子关闭
// 获取父盒子
const pop = document.querySelector('.pop')
// 1. 事件源 a链接
const closeBtn = document.querySelector('.close')
// 2. 注册事件
closeBtn.addEventListener('click', function () {
// 3. 关闭父盒子 主要利用 display:none
pop.style.display = 'none'
})
</script>
</body>
</html>
回调函数
回调函数:当一个函数当做参数来传递给另外一个函数的时候,这个函数就是回调函数(回头调用的函数)
作用:完成某些特定任务
<script>
// 1. 定时器间隔函数,里面第一个参数又是函数,这个匿名函数就是回调函数
setInterval(function () {
console.log('我是回调函数')
}, 1000)
// 2. addEventListener 函数的第二个参数也是函数,这个匿名函数也是回调函数
btn.addEventListener('click', function () {
console.log('我是回调函数')
})
</script>
回调函数本质还是函数,只不过把它当成参数使用
使用匿名函数做为回调函数比较常见
事件监听版本(扩展阅读)
事件监听发展史:
DOM L0 :是 DOM 刚诞生的版本,使用 事件源.on事件类型 来注册事件
DOM L1:DOM级别1 于1998年10月1日成为W3C推荐标准
DOM L2:使用addEventListener注册事件
DOM L3: DOM3级事件模块在DOM2级事件的基础上重新定义了这些事件,也添加了一些新事件类型
我们常用DOM L0 和 DOM L2方式来注册事件:
- DOM0 事件 事件源.on事件类型 = function() { }
btn.onclick = function () {
alert('我是弹窗1')
}
- DOM 2事件事件源.addEventListener(事件类型,事件处理函数)
btn.addEventListener('click', function () {
console.log('我是回调函数')
})
区别:
on 方式同名事件会被覆盖 -> 场景:一个Dom元素身上同名事件只注册一次
addEventListener则不会 -> 场景:一个Dom元素身上同名事件要注册多次
事件类型
将众多的事件类型可分为:
- 鼠标事件
- 键盘事件
- 表单事件
- 焦点事件等
我们逐一展开学习。
事件类型的大小写敏感的字符串,统一用小写字母
鼠标事件
鼠标事件是指跟鼠标操作相关的事件,如单击、经过等。
<body>
<div class="box"></div>
<script>
// 鼠标事件类型
const box = document.querySelector('.box')
// 1. 鼠标点击
box.addEventListener('click', function () {
console.log('我点击了盒子')
})
// 2. 鼠标进入
box.addEventListener('mouseenter', function () {
console.log('我鼠标经过了盒子')
})
// 3. 鼠标离开
box.addEventListener('mouseleave', function () {
console.log('我鼠标离开了盒子')
})
</script>
</body>
随堂练习
需求:实现轮播图点击切换功能,功能要求如下
- 进入页面时轮播图按照顺序自动轮播 - 使用setInterval技术
- 当鼠标进入轮播图时,停止自动轮播,离开轮播后,恢复自动轮播 -使用mouseenter和mouseleave事件
- 当点击>按钮时,轮播图顺序切换图片,点击<按钮时,轮播图倒序切换图片-使用click事件
<!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>
// 初始数据对象数组
const sliderData = [
{ 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)' },
]
// 1. 利用随机数选取数组中的一个对象
let index = 0
function setSwiperData() {
let data = sliderData[index]
// 将data中的各种属性设置到网页的相关元素即可
// 2. 利用选取的对象来更换图片
// 需求:把图片元素的地址换成数据里面的图片地址
// 2.1 获取图片元素
const imgBox = document.querySelector('.slider-wrapper img')
// 2.2 把随机生成的图片地址 赋值给 图片元素.src
imgBox.src = data.url
// 3. 更换文字内容
// 3.1 获取文字盒子 p
const pBox = document.querySelector('.slider-footer p')
// 3.2 把随机生成的文字赋值给 p元素.innerText 或者 innerHTML
pBox.innerHTML = data.title
// 4. 更换背景颜色 slider-footer 盒子
// 4.1 获取 slider-footer 盒子
const divBox = document.querySelector('.slider-footer')
// 4.2 把随机生成的背景颜色赋值给 footer元素 style
divBox.style.backgroundColor = data.color
// 5. 更换小圆点
// 5.1 先选择对应的小圆点
const liBox = document.querySelector(`.slider-indicator li:nth-child(${index + 1})`)
// 5.2 让选出来的小圆点高亮显示
// 将已经有小圆点样式的li标签上的class的active移除
const activeBox = document.querySelector('.active')
activeBox.classList.remove('active')
liBox.classList.add('active')
}
let timerId = setInterval(function () {
// 将index加1
index++
if (index >= sliderData.length) {
// 将index重置回0
index = 0
}
setSwiperData()
}, 1000)
/*
基于昨天的综合案例,扩展如下需求
1. 鼠标进入盒子,停止自动轮播
-> 技术拆解
1. 事件源:div.slider
2. 事件类型: mouseenter
3. 事件函数代码逻辑:clearInterval(定时器的id)
2. 离开盒子,重新开启自动轮播
->技术拆解
1. 事件源:div.slider
2. 事件类型: mouseleave
3. 事件函数代码逻辑:setInterval重新开启
2. 用户点击< 和 > 自动切换图片
技术拆解:
1. 事件源: < .prev > .next
2. 事件类型:点击事件 click
3. 事件函数
*/
/*
需求1:
1. 鼠标进入盒子,停止自动轮播
-> 技术拆解
1. 事件源:div.slider
2. 事件类型: mouseenter
3. 事件函数代码逻辑:clearInterval(定时器的id)
*/
const silderBox = document.querySelector('.slider')
silderBox.addEventListener('mouseenter', function () {
// clearInterval(定时器的id)
clearInterval(timerId)
})
/*
需求2:
2. 离开盒子,重新开启自动轮播
->技术拆解
1. 事件源:div.slider
2. 事件类型: mouseleave
3. 事件函数代码逻辑:setInterval重新开启
*/
silderBox.addEventListener('mouseleave', function () {
timerId = setInterval(function () {
// 将index加1
index++
if (index >= sliderData.length) {
// 将index重置回0
index = 0
}
setSwiperData()
}, 1000)
})
/*
需求3:
2. 用户点击< 和 > 自动切换图片
技术拆解:
1. 事件源: < .prev > .next
2. 事件类型:点击事件 click
3. 事件函数
*/
const nextBox = document.querySelector('.next')
nextBox.addEventListener('click', function () {
// 将index加1
index++
if (index >= sliderData.length) {
// 将index重置回0
index = 0
}
setSwiperData()
})
const prevBox = document.querySelector('.prev')
prevBox.addEventListener('click',function(){
// index减1
index--
if(index <0){
// 如果为负数,则让图片从数组的最后一个数据开始轮播
index = sliderData.length - 1
}
setSwiperData()
})
</script>
</body>
</html>
焦点事件
主要是针对于表单是否获得光标的事件, 获得焦点 focus 、失去焦点 blur
<!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>
[type=text] {
width: 245px;
height: 50px;
padding-left: 20px;
border: 1px solid #ccc;
font-size: 17px;
outline: none;
}
</style>
</head>
<body>
<input type="text" class="search-text">
<input type="text" class="search">
<script>
// 1. 焦点事件(手动触发)
const search_text = document.querySelector('.search-text')
// 1.1 获得焦点 focus
search_text.addEventListener('focus', function () {
console.log('获得了焦点')
})
// 1.2 失去焦点 blur
search_text.addEventListener('blur', function () {
console.log('失去了焦点')
})
// 2. 拓展 自动获得焦点 focus() 自动失去焦点 blur()
// 2.1 语法: 元素.focus() 比如百度首页搜索框自动获得焦点
const search = document.querySelector('.search')
search.focus()
</script>
</body>
</html>
键盘事件和 input事件
事件 | 触发时机 | 得到表单值 |
keydown | 按下键盘时触发 | 内容获取-不完整 |
keyup | 弹起键盘时触发 | 输入内容-完整 |
input | 表单value发生变化时触发 | 输入内容 -完整 |
<!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>input事件和键盘事件</title>
<style>
textarea {
width: 300px;
height: 30px;
padding: 10px;
border-color: transparent;
outline: none;
resize: none;
background: #f5f5f5;
border-radius: 4px;
}
</style>
</head>
<body>
<textarea id="tx" placeholder="发一条友善的评论" rows="2"></textarea>
<script>
// 获取元素
const tx = document.querySelector('#tx')
// 1. 键盘事件
// 1.1 键盘按下事件 keydown 当我们按下键盘的时候就触发
tx.addEventListener('keydown', function () {
console.log('我是keydown事件' + tx.value)
})
// 1.2 键盘弹起事件 keyup 当我们键盘弹起的时候就触发
tx.addEventListener('keyup', function () {
console.log('我是keyup事件' + tx.value)
})
// 2. 用户输入事件 input ,是表单value的值发生变化的时候触发
tx.addEventListener('input', function () {
console.log('我是input事件' + tx.value)
})
// 3. 注意事项
// 3.1 执行顺序 keydown → input → keyup
// 3.2 keydown 获取值的时候得不到最后一次按键的值, keyup和input可以得到用户输入内容
</script>
</body>
</html>
注意事项
- 执行顺序 keydown → input → keyup
- keydown 获取值的时候得不到最后一次按键的值, keyup和input可以得到用户输入内容
事件对象
事件对象是什么?
注册事件中,回调函数的第一个参数就是事件对象,一般命名为event、ev、e
- 事件对象里保存了:事件触发时的相关信息,包含属性和方法
- 例如:鼠标点击事件中,事件对象就存了事件源的信息
使用场景
- 可以判断用户按下哪个键,比如按下回车键可以发布新闻
- 可以判断鼠标点击了哪个元素,从而做相应的操作
<body>
<div class="box"></div>
<textarea id="tx" placeholder="发一条友善的评论" rows="2"></textarea>
<script>
// 事件对象
const box = document.querySelector('.box')
box.addEventListener('click', function (e) {
console.log(e)
console.log(e.target) // target保存了事件源信息
})
const tx = document.querySelector('#tx')
tx.addEventListener('keyup', function (e) {
// e 就是事件对象
// console.log(e)
// console.log(e.key) // a
// 用户如果按下的是回车键,则弹出框提示按下了回车键
if (e.key === 'Enter') {
alert('您按下了回车键')
}
})
</script>
</body>
事件对象常见属性
事件回调函数的【第1个参数】即所谓的事件对象,通常习惯性的将这个对数命名为 event
、ev
、ev
。
随堂练习
需求:按下回车键,可以发布评论
功能:
①:按下回车,可以显示评论信息,并且评论内容显示到对应位置
②:输入完毕,文本域清空内容
<!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 {
width: 800px;
display: flex;
justify-content: flex-end;
}
.wrapper textarea {
height: 50px;
flex: 1;
padding: 10px;
border-radius: 4px;
border-color: #e4e4e4;
background: #fff;
outline: none;
resize: none;
}
.wrapper button {
width: 70px;
margin-left: 10px;
border: none;
color: #fff;
background: #00aeec;
border-radius: 4px;
cursor: pointer;
}
.wrapper .total {
margin-right: 80px;
margin-top: 5px;
color: #999;
}
.list {
width: 800px;
border: 1px solid #efce9c;
background-color: rgb(231, 238, 191);
padding: 10px;
}
.list p {
font-size: 12px;
}
</style>
</head>
<body>
<div class="wrapper">
<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">
<p>评论信息:</p>
<p class="msg">善语结善缘~~请发表你的评论</p>
</div>
<script>
/*
需求:
1. 获取用户在文本域元素中的内容,并且回车表示发表动作
-> 找事件源 id="tx" -> 事件类型:keyup
2. 获取到文本内容之后,将这个内容更新到p元素
->事件函数要完成的事情
*/
const textBox = document.querySelector('#tx')
textBox.addEventListener('keyup', function (e) {
// 判断如果用户按的是回车键,表示发表评论
if (e.key === 'Enter') {
// 2. 获取到文本内容之后,将这个内容更新到p元素
document.querySelector('.msg').innerHTML = textBox.value
// 清空文本域中的内容
textBox.value = ''
}
})
</script>
</body>
</html>
环境对象-this
环境对象:指的是函数内部特殊的 this , 它指向一个对象,调用方式不一样,this指向的对象也不一样
作用:弄清楚this的指向,可以让我们更方便编写代码
function fn() {
console.log(this) // this 指向哪个对象?
}
// fn() // 直接调用函数fn(),其实相当于是 window.fn()
window.fn()
const obj = {
uname: '佩奇',
sayHi: function () {
console.log(this) // this指向哪个对象?
}
}
obj.sayHi()
const btn1 = document.querySelector('button')
btn1.addEventListener('click', function () {
console.log(this) // this指向哪个对象?
})
<body>
<button>点击</button>
<script>
// 环境对象 this 粗略规则: 谁调用函数,this就指向谁
// 1. 全局环境
// console.log(this) // this 指向 window 全局对象
// 2. 普通函数
function fn() {
console.log(this) // this 指向 window 全局对象
}
window.fn()
// 3. 对象方法
const obj = {
uname: '佩奇',
sayHi: function () {
console.log(this) // this 指向 obj对象
}
}
obj.sayHi()
// 4. 事件
const btn1 = document.querySelector('button')
btn1.addEventListener('click', function () {
console.log(this) // this 指向 btn 这个对象
})
</script>
</body>
特点:
- 函数的调用方式不同,this 指代的对象也不同
- 【谁调用, this 就是谁】 是判断 this 指向的粗略规则
- 直接调用函数,其实相当于是 window.函数,所以 this 指代 window
排他思想
是一种思路,目的是突出显示某个元素
比如,有多个元素,当鼠标点击某个元素时,只有被点击的元素会添加高亮样式,其余的元素移除样式
口诀:注意顺序
①:排除其他人
②:保留我自己
基本用法
<!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>
.pink {
background-color: pink;
}
</style>
</head>
<body>
<button class="pink">按钮1</button>
<button class="pink">按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
<script>
// 1. 向5个按钮注册点击事件
const bts = document.querySelectorAll('button')
for(let i = 0;i<bts.length;i++){
bts[i].addEventListener('click',function(e){
// console.log(e.target)
// 将其他元素身上的pink类移除掉
const pinks = document.querySelectorAll('.pink')
for(let j=0;j<pinks.length;j++){
pinks[j].classList.remove('pink')
}
// 谁点击了就加上pink这个类到自己身上
e.target.classList.add('pink')
})
}
</script>
</body>
</html>