国内知名的网站设计公司精选网页设计
目录
一、事件监听
1. 事件监听的基本概念
2. 使用 addEventListener
二、事件对象
1. 常见事件对象属性与方法
2. 示例代码
三、环境对象(this)的指向
1. 传统函数中的 this
2. 箭头函数中的 this
3. 结论
4. 注意事项
三、回调函数(Callback Function)
1. 回调函数的特点
2. 综合应用:事件对象、this 与回调
3. 常见问题与解决方案
示例:随机轮播图
一、事件监听
1. 事件监听的基本概念
-
事件:用户或浏览器触发的动作,如点击、滚动、键盘输入等。
-
监听器(Listener):事件发生时执行的函数。
-
两种绑定方式:
-
HTML 属性:
<button onclick="handleClick()">
(不推荐,混合逻辑与结构)。 -
DOM API:
addEventListener
(推荐,灵活且可维护)。
-
2. 使用 addEventListener
-
语法:
element.addEventListener(eventType, handler [, options]);
-
参数:
-
eventType:事件类型字符串(如
"click"
、"keydown"
)。 -
handler:事件触发时调用的函数。
-
options(可选):配置对象或布尔值,控制捕获/冒泡阶段、一次性执行等。
-
-
步骤:
-
获取 DOM 元素
-
通过
addEventListener
方法为 DOM 节点添加事件监听 -
等待事件触发,如用户点击了某个按钮时便会触发
click
事件类型 -
事件触发后,相对应的回调函数会被执行
-
-
示例:
const button = document.querySelector('button'); button.addEventListener('click', function(event) {console.log('按钮被点击!'); });
二、事件对象
当事件触发时,浏览器会自动创建一个 事件对象(event
),并将其作为参数传递给事件处理函数。该对象包含与事件相关的所有信息,例如触发事件的元素、事件类型、坐标位置、按键信息等。
1. 常见事件对象属性与方法
-
常用属性/方法:
-
event.target
:触发事件的元素(如点击的具体子元素)。 -
event.currentTarget
:绑定事件的元素(等同于this
)。 -
event.stopPropagation()
:阻止事件继续传播(冒泡或捕获)。 -
event.preventDefault()
:阻止默认行为(如表单提交、链接跳转)。 -
event.type
:事件类型(如"click"
)。
-
属性/方法 | 说明 | 示例场景 |
---|---|---|
event.target | 触发事件的实际元素(可能是事件冒泡中的子元素) | 点击子元素时,target 指向子元素 |
event.currentTarget | 绑定事件的元素(等同于 this ,在事件处理函数中指向绑定事件的元素) | 事件委托中,currentTarget 指向父元素 |
event.type | 事件类型(如 "click" 、"keydown" ) | 判断事件类型以执行不同逻辑 |
event.preventDefault() | 阻止事件的默认行为(如阻止链接跳转、表单提交) | 表单验证失败时阻止提交 |
event.stopPropagation() | 阻止事件继续传播(停止捕获或冒泡) | 避免父元素的事件监听器触发 |
event.stopImmediatePropagation() | 阻止同一元素上的其他监听器执行 | 优先级高于 stopPropagation ,阻止后续监听器 |
event.clientX / clientY | 鼠标相对于浏览器窗口的坐标(不包含滚动偏移) | 实现拖拽效果时获取鼠标位置 |
event.pageX / pageY | 鼠标相对于文档的坐标(包含滚动偏移) | 绘制画布时准确定位 |
event.key | 键盘事件的按键值(如 "Enter" 、"a" ) | 监听回车键提交表单 |
event.relatedTarget | 关联元素(如 mouseover 时表示鼠标来自哪个元素,focusout 时表示即将获得焦点的元素) | 实现下拉菜单的悬停交互 |
2. 示例代码
document.querySelector('button').addEventListener('click', function(event) {console.log('事件类型:', event.type); // "click"console.log('触发元素:', event.target.tagName); // 可能是子元素console.log('绑定元素:', event.currentTarget.tagName); // BUTTONevent.preventDefault(); // 阻止默认行为(如表单提交)
});
三、环境对象(this)的指向
在事件处理函数中,this
的指向取决于函数的定义方式:
1. 传统函数中的 this
-
指向绑定事件的元素(与
event.currentTarget
相同)。 -
示例
2. 箭头函数中的 this
-
继承外层作用域的
this
(通常是window
或外层函数上下文)。 -
示例:
button.addEventListener('click', () => {console.log(this === window); // true(假设外层是全局作用域) });
3. 结论
-
this
本质上是一个变量,数据类型为对象 -
函数的调用方式不同
this
变量的值也不同 -
【谁调用
this
就是谁】是判断this
值的粗略规则
4. 注意事项
-
避免在需要
this
指向元素时使用箭头函数。 -
需要访问元素时,优先使用
event.currentTarget
(兼容性更好)。
三、回调函数(Callback Function)
如果将函数 A 做为参数传递给函数 B 时,我们称函数 A 为回调函数。
1. 回调函数的特点
-
参数传递:
-
默认接收
event
对象作为参数。 -
若需传递自定义参数,需封装在匿名函数中:
const handler = (message) => {console.log(message); }; button.addEventListener('click', () => handler('按钮被点击!'));
-
-
匿名函数与命名函数:
-
匿名函数:直接定义在
addEventListener
中,但无法直接移除。button.addEventListener('click', function() { /* ... */ });
<script>// 调用定时器,匿名函数做为参数setInterval(function () {console.log('我是回调函数...');}, 1000); </script>
-
命名函数:需预先定义,便于复用和移除。
function handleClick() { /* ... */ } button.addEventListener('click', handleClick); button.removeEventListener('click', handleClick); // 可成功移除
<script>function fn() {console.log('我是回调函数...');}// 调用定时器setInterval(fn, 1000); </script>
-
-
内存管理:
-
若回调函数引用外部变量或 DOM 元素,可能导致内存泄漏(需及时移除监听)。
-
2. 综合应用:事件对象、this 与回调
<div id="container"><button class="btn">点击我</button>
</div>
const container = document.querySelector('#container');
const button = document.querySelector('.btn');// 传统函数中 this 指向绑定元素
button.addEventListener('click', function(event) {console.log('this:', this); // <button> 元素console.log('currentTarget:', event.currentTarget); // <button> 元素console.log('target:', event.target); // <button> 元素(无子元素时与 currentTarget 相同)
});// 事件委托:父元素监听子元素事件
container.addEventListener('click', function(event) {if (event.target.classList.contains('btn')) {console.log('点击的按钮:', event.target);event.stopPropagation(); // 阻止冒泡到更外层}
});// 箭头函数中的 this(假设外层为全局作用域)
button.addEventListener('click', () => {console.log('箭头函数中的 this:', this); // window 或 undefined(严格模式)
});
3. 常见问题与解决方案
问题场景 | 原因分析 | 解决方案 |
---|---|---|
this 指向不符合预期 | 使用了箭头函数 | 改用传统函数,或通过 event.currentTarget 获取元素 |
无法移除事件监听 | 回调函数为匿名函数 | 使用命名函数,并确保 removeEventListener 参数一致 |
事件委托中误判 event.target | 子元素嵌套导致 target 不准确 | 使用 closest 方法向上查找匹配元素:event.target.closest('.btn') |
高频事件(如 scroll )卡顿 | 回调函数执行过于频繁 | 使用 节流(throttle) 或 防抖(debounce) 优化 |
示例:随机轮播图
<!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></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 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)' },]function slider(i) {const img = document.querySelector('.slider-wrapper img')img.src = sliderData[i].urlconst title = document.querySelector('.slider-footer p')title.textContent = sliderData[i].titleconst bgc = document.querySelector('.slider-footer')bgc.style.backgroundColor = sliderData[i].colorconst li = document.querySelector(`.slider-indicator li:nth-child(${i + 1})`)li.classList.add('active')}function clearSlider(i) {const li = document.querySelector(`.slider-indicator li:nth-child(${i + 1})`)li.classList.remove('active')}let i = 0slider(i)//1.手动轮播const next = document.querySelector('.toggle .next')next.addEventListener('click', function () {clearSlider(i)i++;if (i === 8)i = 0slider(i)})const prev = document.querySelector('.toggle .prev')prev.addEventListener('click', function () {clearSlider(i)i--;if (i === -1)i = 7slider(i)})//2.自动轮播// let timer = setInterval(function () {// clearSlider(i)// i++;// if (i === 8)// i = 0// slider(i)// }, 1000)</script>
</body></html>