【JavaScript】十五、事件对象与环境对象
文章目录
- 1、事件对象
- 1.1 获取事件对象
- 1.2 常用属性
- 1.3 案例:回车发布评论
- 2、环境对象this
- 3、回调函数
- 4、案例:tab切换
- 5、案例:全选文本框📖
1、事件对象
事件对象:
- 也是个对象,object,里面存储了事件触发时的相关信息
- 比如鼠标点击事件中,可以获取鼠标点了哪个位置
使用场景:
- 从事件对象中获取数据,作出相应的操作
- 比如判断用户按下的键是回车的话,就发布评论
1.1 获取事件对象
- 在事件绑定的回调函数的第一个参数就是事件对象
- 一般命名为event、ev、e
1.2 常用属性
-
type:获取当前的事件类型
-
clientX/clientY:获取光标相对于浏览器可见窗口左上角的位置
-
offsetX/offsetY:获取光标相对于当前DOM元素左上角的位置
-
key:用户按下的键盘键的值,现在不提倡使用keyCode
1.3 案例:回车发布评论
实现思路:
-
用键盘事件 keydown 或者 keyup ,但多用keyup,用keydown的话,按下不松手会一直多次触发事件
-
如果用户按下的是回车键盘,则发布信息
-
发布信息,这里没有后端接口create + list接口,用数据渲染到对应标签内部模拟
<!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">2025-04-03 00:21:11</p>
</div>
</div>
</div>
<script>
const tx = document.querySelector('#tx')
const total = document.querySelector('.total')
// 显示和隐藏文本字数统计结果
tx.addEventListener('focus', function () {
total.style.opacity = 1 // opacity,透明度样式,相比display,显示和隐藏更加柔和
})
tx.addEventListener('blur', function () {
total.style.opacity = 0
})
// 文本事件,做字数统计并渲染
tx.addEventListener('input', function () {
// tx.value是获取到输入的字符串,后面.length获取字符串长度(包装类型)
total.innerHTML = `${tx.value.length}/200字`
})
// 键盘事件
const item = document.querySelector('.item')
const text = document.querySelector('.text') //评论内容
tx.addEventListener('keyup', function (e) {
// trim方法去除字符串左右两端端空格,中间的空格仍然保留不变
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>
效果:
2、环境对象this
- 环境对象,即函数内部的特殊变量this
- this代表这个函数运行时所处的环境
- 函数调用方式不同,this指代的对象也不同,粗略判断为:谁调用这个函数,this就指代谁
<body>
<button>按钮</button>
<script>
function fn() {
console.log(this)
}
// 其实是window.fn()
fn()
// btn这个DOM对象在调用下面的function函数
const btn = document.querySelector('button')
btn.addEventListener('click', function () {
console.log(this)
})
</script>
</body>
直接调用函数,其实相当于是 window.函数,所以 this 指代 window,而下面监听点击事件,则是button对象在调用,所以this就是这个DOM对象,因此,像实现点击按钮后按钮变色
以下两种写法等价:
3、回调函数
将函数 A 做为参数传递给函数 B 时,我们称函数 A 为回调函数
经常使用匿名函数做为回调函数
4、案例:tab切换
需求:鼠标经过不同的选项卡,底部可以显示 不同的内容
实现思路:获取所有的a标签,遍历绑定鼠标移入事件,数据的切换,通过样式控制显示和隐藏
<!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>
// 全选所有的a标签
const as = document.querySelectorAll('.tab-nav a')
// 遍历给每个a标签鼠标经过,变成高亮并切换对应的数据
for (let i = 0; i < as.length; i++) {
as[i].addEventListener('mouseenter', function () {
// 移除有高亮样式的,排它
document.querySelector('.tab-nav .active').classList.remove('active')
// 谁在调用这个匿名函数?是as[i],所以as[i]就是这个匿名函数的this
this.classList.add('active')
// 修改数据
document.querySelector('.tab-content .active').classList.remove('active')
// 对应序号item对象的数据显示,数组序号从0开始,但item从1开始,所以+1
document.querySelector(`.tab-content .item:nth-child(${i + 1})`).classList.add('active')
})
}
</script>
</body>
</html>
效果:
5、案例:全选文本框📖
需求1:大按钮控制所有小按钮,用户点击全选,则下面复选框全部选择,取消全选则全部取消
需求2:小按钮控制大按钮,下面某一项被取消选择了,则全选也要被取消
点击全选,下面每一项都选择,再点击全选,每一项都取消选择的实现思路是:
- 点击全选的复选框,获取checked属性
- 将下面所有小复选框的状态,统统更新成和全选复选框一致的
而第二个需求的实现,需要借助一个选择器:
<!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>
/* .ck是类选择器,对应我下面的class="ck",
而.ck:checked则是css复选框选择器,选择被勾选的复选框 ,
因此,下面这个代码可以实现:勾选后,复选框变大*/
.ck:checked {
width: 40px;
height: 40px;
}
</style>
</head>
<body>
<input type="checkbox" name="" id="" class="ck">
<input type="checkbox" name="" id="" class="ck">
<input type="checkbox" name="" id="" class="ck">
<input type="checkbox" name="" id="" class="ck">
</body>
</html>
效果:勾选后,被.ck:checked选中,样式生效,变大
借助这个选择器,获取小复选框的个数,和已被checked的小复选框的个数,相等则表示全选,否则,更新全选框的checked为false
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
* {
margin: 0;
padding: 0;
}
table {
border-collapse: collapse;
border-spacing: 0;
border: 1px solid #c0c0c0;
width: 500px;
margin: 100px auto;
text-align: center;
}
th {
background-color: #09c;
font: bold 16px "微软雅黑";
color: #fff;
height: 24px;
}
td {
border: 1px solid #d0d0d0;
color: #404060;
padding: 10px;
}
.allCheck {
width: 80px;
}
</style>
</head>
<body>
<table>
<tr>
<th class="allCheck">
<input type="checkbox" name="" id="checkAll"> <span class="all">全选</span>
</th>
<th>商品</th>
<th>商家</th>
<th>价格</th>
</tr>
<tr>
<td>
<input type="checkbox" name="check" class="ck">
</td>
<td>小米手机</td>
<td>小米</td>
<td>¥1999</td>
</tr>
<tr>
<td>
<input type="checkbox" name="check" class="ck">
</td>
<td>小米净水器</td>
<td>小米</td>
<td>¥4999</td>
</tr>
<tr>
<td>
<input type="checkbox" name="check" class="ck">
</td>
<td>小米电视</td>
<td>小米</td>
<td>¥5999</td>
</tr>
</table>
<script>
// 需求1:
// 获取全选复选框的DOM对象
const tableHead = document.querySelector('#checkAll')
// 下面每一项的DOM对象
const cks = document.querySelectorAll('.ck')
tableHead.addEventListener('click', function (e) {
console.log(this.checked) //表单元素属性checked,输出是true或者false
// 遍历所有的小复选框☑️,让小复选框的checked = 表头复选框的checked
for (let i = 0; i < cks.length; i++) {
cks[i].checked = this.checked
}
})
// 需求2:
// 给所有的小复选框添加点击事件,里面比较checked的小复选框的总数,来更新大复选框的状态
for (let i = 0; i < cks.length; i++) {
cks[i].addEventListener('click', function () {
// 获取所有已勾选的小复选框
const checkedCks = document.querySelectorAll('.ck:checked')
if (checkedCks.length === cks.length) {
tableHead.checked = true
} else {
tableHead.checked = false
}
// 当然也可以三元
// tableHead.checked = checkedCks.length === cks.length
})
}
</script>
</body>
</html>
效果: