大白话 在JavaScript 如何阻止事件冒泡和事件默认行为?
引言
凌晨两点,测试小姐姐发来一段录屏:用户点击页面底部的“返回顶部”按钮,结果不仅触发了返回顶部,还顺带提交了旁边的表单,甚至把整个页面的弹窗都给关掉了。你盯着代码里的三个click
事件绑定,冷汗瞬间浸湿了后背——这已经是本周第三次因为事件冒泡导致的交互灾难了。
作为前端开发,我们每天都在和用户交互打交道。但你是否也曾遇到过这样的情况:点击一个子元素,父元素的事件也跟着触发;明明阻止了表单提交,却还是跳转到了新页面;写了e.preventDefault()
却发现毫无作用,控制台还报错e is undefined
。
别以为事件冒泡和默认行为只是“点一下触发多个事件”这么简单。当产品经理拿着原型图问“为什么点击弹窗里的关闭按钮,背景层也跟着消失了”时,你才发现自己根本没处理事件冒泡;当用户投诉“输入框按回车会刷新页面”时,你才意识到忘了阻止表单的默认提交行为。
这篇文章不会干巴巴地讲stopPropagation()
和preventDefault()
的语法,而是用前端人都懂的大白话,告诉你为什么同样是处理点击事件,有人能精准控制触发范围,有人却让事件像脱缰的野马四处乱窜;为什么别人的表单能乖乖等待验证完成再提交,你的表单却总是“自作主张”。就像硝酸甘油能缓解心绞痛一样,这篇指南能让你在面对混乱的事件交互时,保持清晰的逻辑,高效解决问题。
问题场景
场景1:“弹窗连环炸”的冒泡惨案
小周开发的电商详情页,有一个“加入购物车”的弹窗,弹窗里有“确定”按钮,弹窗外层有半透明的遮罩层。产品要求点击遮罩层时关闭弹窗,但点击弹窗内部(包括按钮)时不关闭。结果用户点击“确定”按钮后,不仅执行了加入购物车的逻辑,弹窗也跟着关闭了。
痛点:事件冒泡就像在水里扔石头,涟漪会从落点一直扩散到岸边。点击子元素时,事件会顺着DOM树向上传播,触发所有祖先元素的同名事件。就像你按了家里的灯开关,结果邻居家的灯也跟着亮了,这显然不是你想要的结果。
场景2:“表单私奔”的默认行为
小王做的登录页面,表单里有用户名和密码输入框。用户输入一半按了回车,表单直接提交跳转了,之前填的内容全没了。产品经理怒怼:“没填完怎么能提交?就不能等用户点登录按钮吗?”
痛点:浏览器的默认行为就像自带的“自动驾驶模式”,某些元素在特定操作下会自动执行预设动作——表单提交、链接跳转、右键菜单弹出……这些默认行为虽然方便,但在需要自定义交互时就会帮倒忙,就像你想手动开车,车却自己加速冲了出去。
场景3:“事件拦截失效”的调试噩梦
小李在代码里写了e.preventDefault()
阻止链接跳转,结果点击链接还是跳走了。他反复检查拼写没错,最后才发现事件处理函数里的参数写成了event
,但调用时用了e
,导致e
是undefined
。这种低级错误让他排查了整整一下午。
痛点:阻止事件的方法看似简单,却藏着不少坑——参数名不匹配、忘了传参、在事件捕获阶段调用无效……这些问题就像医生开对了药,却给病人吃错了剂量,不仅没效果,还可能引发副作用。
场景4:“第三方插件冲突”的连锁反应
小张在项目里用了一个日历插件,同时自己写了点击文档空白处关闭弹窗的逻辑。结果点击日历选择日期时,弹窗总是自动关闭。排查后发现,日历插件的点击事件冒泡到了文档,触发了关闭逻辑。
痛点:当页面引入多个库或插件时,事件冒泡可能引发不可预知的冲突。就像多个部门共用一个会议室,A部门刚要开会,B部门的人推门就进,整个工作节奏全被打乱了。
技术原理
事件流:DOM的“通讯网络”
浏览器处理事件的过程分为三个阶段,就像快递的运输流程:
- 捕获阶段:事件从window对象向下传播到目标元素的父级(类似快递从仓库发往片区集散点)
- 目标阶段:事件到达目标元素(类似快递送到收件人楼下)
- 冒泡阶段:事件从目标元素的父级向上传播回window对象(类似快递签收后,消息回传到仓库)
我们平时用addEventListener
绑定的事件,默认在冒泡阶段触发。可以通过第三个参数useCapture
(默认false)来切换到捕获阶段。
事件冒泡:为什么点击子元素会触发父元素事件?
当你点击一个元素时,浏览器会先触发该元素的事件处理函数,然后顺着DOM树向上,依次触发每个父元素的同名事件处理函数。这种传播机制就是事件冒泡(Bubbling)。
<div class="grandpa">
<div class="father">
<div class="son">点击我</div>
</div>
</div>
点击son
时,事件触发顺序是:son → father → grandpa → body → html → document → window
这种机制的设计初衷是方便事件委托(Event Delegation)——只需给父元素绑定一次事件,就能处理所有子元素的事件,减少内存占用。但在不需要这种传播时,就必须手动阻止。
阻止事件冒泡的两种方法
-
标准方法:
event.stopPropagation()
- 属于W3C标准,兼容所有现代浏览器(IE8及以下不支持)
- 作用:阻止事件在冒泡阶段继续向上传播,但不会影响当前元素的其他事件处理函数
-
IE专属方法:
event.cancelBubble = true
- 仅支持IE8及以下浏览器
- 作用和
stopPropagation()
相同,现代项目中已很少使用,但了解它有助于理解兼容性处理
事件默认行为:浏览器的“自动响应”
浏览器为许多元素预设了默认行为:
<a>
标签点击跳转<form>
表单提交<button type="submit">
点击提交表单- 文本框按回车触发表单提交
- 右键点击弹出上下文菜单
- 按F5刷新页面
这些行为是Web发展初期为了简化开发设计的,但在需要自定义交互时,就必须禁用它们。
阻止默认行为的三种方法
-
标准方法:
event.preventDefault()
- W3C标准,现代浏览器通用
- 作用:取消事件的默认行为,但不会阻止事件冒泡
-
return false(仅限特定场景)
- 在DOM0级事件处理程序中(如
onclick="return false"
),相当于同时调用preventDefault()
和stopPropagation()
- 在jQuery的事件处理函数中,
return false
也会同时阻止冒泡和默认行为 - 注意:在原生addEventListener中,
return false
无效!
- 在DOM0级事件处理程序中(如
-
IE专属方法:
event.returnValue = false
- 仅支持IE8及以下,功能同
preventDefault()
- 仅支持IE8及以下,功能同
事件对象:传递信息的“信使”
所有事件处理函数都会接收一个事件对象(Event Object),它包含了事件的详细信息:
type
:事件类型(如click
、keydown
)target
:触发事件的原始元素(目标元素)currentTarget
:当前处理事件的元素(绑定事件的元素)bubbles
:事件是否会冒泡cancelable
:事件是否可以阻止默认行为
正确使用事件对象是阻止事件冒泡和默认行为的前提,很多新手出错都是因为没正确获取这个对象。
代码示例
阻止事件冒泡的代码示例
基础示例:阻止点击事件冒泡
<div id="grandpa" style="padding: 50px; background: red;">
爷爷
<div id="father" style="padding: 50px; background: green;">
爸爸
<div id="son" style="padding: 50px; background: blue;">
儿子
</div>
</div>
</div>
<script>
// 给爷爷绑定点击事件
document.getElementById('grandpa').addEventListener('click', function(e) {
console.log('爷爷被点击了');
});
// 给爸爸绑定点击事件
document.getElementById('father').addEventListener('click', function(e) {
console.log('爸爸被点击了');
// 在这里阻止冒泡,爸爸的事件触发后,不会再传播给爷爷
e.stopPropagation(); // 关键代码:阻止事件继续向上冒泡
});
// 给儿子绑定点击事件
document.getElementById('son').addEventListener('click', function(e) {
console.log('儿子被点击了');
// 如果这里不阻止冒泡,事件会传播给爸爸
// e.stopPropagation(); // 取消注释后,只会触发儿子的事件
});
</script>
执行结果:
- 点击“儿子”:输出“儿子被点击了” → “爸爸被点击了”(因为爸爸阻止了冒泡,爷爷不会触发)
- 如果儿子也阻止冒泡:只输出“儿子被点击了”
兼容IE8的阻止冒泡写法
// 封装一个兼容各浏览器的阻止冒泡函数
function stopBubbling(e) {
// 标准浏览器
if (e && e.stopPropagation) {
e.stopPropagation();
} else {
// IE8及以下
window.event.cancelBubble = true;
}
}
// 使用示例
document.getElementById('son').addEventListener('click', function(e) {
// 处理点击逻辑
console.log('处理儿子的点击事件');
// 调用封装好的函数阻止冒泡
stopBubbling(e || window.event); // 兼容IE的事件对象获取方式
});
事件委托中阻止冒泡的应用
<ul id="list">
<li>项目1</li>
<li>项目2</li>
<li>项目3</li>
<li class="special">特殊项目(点击不触发)</li>
</ul>
<script>
// 事件委托:给父元素ul绑定一次事件,处理所有li的点击
document.getElementById('list').addEventListener('click', function(e) {
// e.target是实际点击的元素
if (e.target.tagName === 'LI') {
// 判断是否是特殊项目
if (e.target.classList.contains('special')) {
console.log('这是特殊项目,不执行操作');
e.stopPropagation(); // 阻止冒泡(如果有上层元素监听click)
return;
}
console.log('点击了项目:' + e.target.textContent);
}
});
// 外层容器的点击事件
document.body.addEventListener('click', function() {
console.log('页面空白处被点击了');
});
</script>
说明:点击普通li会执行操作并触发body的事件,点击特殊li则只输出提示且不触发body事件(因为阻止了冒泡)
阻止默认行为的代码示例
阻止链接跳转
<!-- 普通链接会跳转 -->
<a href="https://www.example.com" id="normalLink">普通链接(会跳转)</a>
<!-- 阻止跳转的链接 -->
<a href="https://www.example.com" id="preventLink">阻止跳转的链接</a>
<script>
// 给需要阻止跳转的链接绑定事件
document.getElementById('preventLink').addEventListener('click', function(e) {
e.preventDefault(); // 阻止默认跳转行为
console.log('链接被点击了,但不会跳转');
// 可以在这里添加自定义逻辑
setTimeout(() => {
console.log('3秒后再跳转');
window.location.href = this.href; // 手动跳转
}, 3000);
});
</script>
阻止表单提交
<form id="myForm" action="/submit" method="get">
<input type="text" name="username" placeholder="用户名">
<button type="submit" id="submitBtn">提交</button>
</form>
<script>
// 获取表单元素
const form = document.getElementById('myForm');
// 给表单绑定提交事件
form.addEventListener('submit', function(e) {
// 获取输入框的值
const username = this.querySelector('input[name="username"]').value;
// 简单验证
if (!username.trim()) {
alert('请输入用户名');
e.preventDefault(); // 验证失败,阻止提交
return;
}
// 验证通过,可以提交(不阻止默认行为)
console.log('表单即将提交');
});
// 也可以给提交按钮绑定点击事件来阻止
document.getElementById('submitBtn').addEventListener('click', function(e) {
const username = form.querySelector('input[name="username"]').value;
if (!username.trim()) {
alert('请输入用户名');
e.preventDefault(); // 阻止按钮的默认提交行为
}
});
</script>
阻止右键菜单(上下文菜单)
<div id="noRightClick" style="width: 200px; height: 200px; background: yellow;">
这里不能右键点击
</div>
<script>
// 监听contextmenu事件(右键菜单事件)
document.getElementById('noRightClick').addEventListener('contextmenu', function(e) {
e.preventDefault(); // 阻止默认右键菜单
alert('别右键点击我,有话好好说');
});
</script>
阻止回车提交表单
<form id="searchForm">
<input type="text" name="keyword" placeholder="搜索关键词">
<button type="button" id="searchBtn">搜索</button>
</form>
<script>
const form = document.getElementById('searchForm');
const input = form.querySelector('input');
// 监听输入框的键盘事件
input.addEventListener('keydown', function(e) {
// 判断是否按的是回车键(keyCode为13)
if (e.keyCode === 13) {
e.preventDefault(); // 阻止回车触发的默认提交
console.log('按了回车,执行自定义搜索逻辑');
// 调用搜索函数
search();
}
});
// 搜索按钮点击事件
document.getElementById('searchBtn').addEventListener('click', search);
// 搜索逻辑
function search() {
const keyword = input.value.trim();
if (keyword) {
console.log('搜索:' + keyword);
// 这里写实际的搜索逻辑
} else {
alert('请输入搜索关键词');
}
}
</script>
同时阻止冒泡和默认行为的示例
<a href="https://example.com" id="link" style="display: block; padding: 20px; background: pink;">
<span id="span">点击我</span>
</a>
<script>
// 给span绑定点击事件
document.getElementById('span').addEventListener('click', function(e) {
e.stopPropagation(); // 阻止冒泡到a标签
e.preventDefault(); // 阻止a标签的默认跳转(虽然这里是span,但事件对象可以传递)
console.log('span被点击,既不冒泡也不跳转');
});
// 给a标签绑定点击事件
document.getElementById('link').addEventListener('click', function() {
console.log('a标签被点击(如果span没阻止冒泡,这里会触发)');
});
// 给body绑定点击事件
document.body.addEventListener('click', function() {
console.log('body被点击(如果没阻止冒泡,这里会触发)');
});
</script>
return false的特殊用法
<!-- 在DOM0级事件中,return false会同时阻止冒泡和默认行为 -->
<a href="https://example.com" onclick="console.log('点击了链接'); return false;">
点我不会跳转,也不会冒泡
</a>
<script>
// 在原生addEventListener中,return false无效
const link = document.createElement('a');
link.href = 'https://example.com';
link.textContent = '原生绑定的链接';
link.addEventListener('click', function() {
console.log('原生绑定的点击事件');
return false; // 这里的return false没用,仍然会跳转
});
document.body.appendChild(link);
// 在jQuery中,return false会同时阻止冒泡和默认行为
// 需要引入jQuery库
// $('#jqueryLink').click(function() {
// console.log('jQuery绑定的点击事件');
// return false; // 有效:不跳转也不冒泡
// });
</script>
对比效果
操作类型 | 方法 | 作用 | 是否阻止冒泡 | 是否阻止默认行为 | 兼容性 | 适用场景 |
---|---|---|---|---|---|---|
阻止冒泡 | e.stopPropagation() | 停止事件向上传播 | 是 | 否 | IE9+及现代浏览器 | 只需要阻止事件扩散,不影响默认行为 |
阻止冒泡 | e.cancelBubble = true | 停止事件向上传播 | 是 | 否 | IE8及以下 | 兼容古老IE浏览器 |
阻止默认行为 | e.preventDefault() | 取消浏览器预设动作 | 否 | 是 | IE9+及现代浏览器 | 只需要禁用默认行为,允许事件冒泡 |
阻止默认行为 | e.returnValue = false | 取消浏览器预设动作 | 否 | 是 | IE8及以下 | 兼容古老IE浏览器 |
同时阻止 | return false (DOM0级) | 停止传播并取消默认 | 是 | 是 | 所有浏览器 | 简单场景下同时需要两种效果 |
同时阻止 | return false (jQuery) | 停止传播并取消默认 | 是 | 否 | 引入jQuery的项目 | jQuery环境下的快捷写法 |
同时阻止 | 手动组合 | 先阻止冒泡再阻止默认 | 是 | 是 | 所有浏览器 | 需要精确控制的复杂场景 |
面试题回答方法
面试题:如何在JavaScript中阻止事件冒泡和事件默认行为?它们有什么区别?
正常回答方法:
在JavaScript中,阻止事件冒泡和阻止事件默认行为是两种不同的操作,用于控制事件的传播和浏览器的预设行为。
阻止事件冒泡的方法有两种:
- 标准方法:使用
event.stopPropagation()
,该方法会阻止事件在冒泡阶段继续向上传播,但不会影响事件的默认行为。适用于IE9及以上现代浏览器。 - IE兼容方法:设置
event.cancelBubble = true
,功能与stopPropagation()
相同,主要用于IE8及以下浏览器。
阻止事件默认行为的方法有三种:
- 标准方法:使用
event.preventDefault()
,该方法会取消浏览器对当前事件的预设动作(如表单提交、链接跳转),但不会影响事件冒泡。 - IE兼容方法:设置
event.returnValue = false
,功能与preventDefault()
相同,用于IE8及以下浏览器。 return false
:在DOM0级事件处理程序(如onclick
属性)中,return false
会同时阻止事件冒泡和默认行为;在jQuery事件处理函数中也有相同效果,但在原生addEventListener
中无效。
两者的主要区别在于:
- 作用对象不同:事件冒泡针对事件的传播过程,默认行为针对浏览器的预设动作。
- 目的不同:阻止冒泡是为了避免事件触发父元素的同名事件,阻止默认行为是为了禁用浏览器的自带功能,实现自定义交互。
- 方法独立性:阻止冒泡不会影响默认行为,阻止默认行为也不会影响事件冒泡,可根据需求单独或同时使用。
在实际开发中,应根据浏览器兼容性和具体需求选择合适的方法,现代项目推荐使用标准方法,并通过特性检测实现兼容处理。
大白话回答方法:
说白了,阻止事件冒泡和阻止默认行为就是两件事:
阻止事件冒泡就像“隔音处理”。比如你在卧室听歌,不想让客厅的人听到,就关上门。点击网页里的按钮时,事件本来会像声音一样传到父元素、爷爷元素,用stopPropagation()
就能把这个“声音”挡住,让上层元素听不见。
阻止默认行为就像“取消自动操作”。浏览器有很多自带的“强迫症”:点链接就跳转、按回车就提交表单、右键就出菜单……这些行为有时候很烦人。用preventDefault()
就能让浏览器“别乱动”,听我们的指挥。
具体怎么用呢?简单说:
- 想不让事件往上跑,就用
e.stopPropagation()
- 想不让浏览器瞎自动,就用
e.preventDefault()
- 老IE浏览器比较特殊,得用
e.cancelBubble = true
和e.returnValue = false
- 还有个偷懒的
return false
,在老式写法里能同时搞定两件事,但在现代写法里经常不好使,所以别乱用
举个例子:点击弹窗里的按钮,既要执行按钮的功能,又不想让弹窗关闭(阻止冒泡),这时候用stopPropagation()
;点击表单的提交按钮,想先验证内容再决定是否提交,这时候用preventDefault()
拦住默认提交,等验证通过了再手动提交。
记住一点:这俩操作互不影响,想同时用就一起写,想单独用就分开写,看你具体要解决啥问题。
总结
事件冒泡和默认行为是JavaScript事件处理中的两个核心概念,理解并掌握它们的控制方法,是写出流畅交互的前提。
事件冒泡就像水中涟漪,会从触发点向上扩散,stopPropagation()
能有效阻止这种扩散,避免父元素的事件被误触发。这在处理嵌套元素的交互(如弹窗、下拉菜单)时特别重要,能防止“点A触发B”的乌龙事件。
浏览器的默认行为是把双刃剑,方便了基础交互却限制了自定义需求。preventDefault()
就像一把“总开关”,能禁用这些预设动作,让我们自由实现表单验证、自定义链接跳转等功能。
实际开发中要注意:
- 事件对象是基础,必须正确获取和传递
- 现代项目优先用
stopPropagation()
和preventDefault()
return false
有坑,非必要不用- 处理第三方插件时,注意事件冒泡可能引发的冲突
记住这些要点,面对复杂的交互场景时,你就能像经验丰富的交通指挥家,让各种事件按规则有序进行,而不是变成一团乱麻。
扩展思考
扩展思考1:事件委托和事件冒泡是什么关系?
事件委托(Event Delegation)是一种利用事件冒泡机制实现的编程模式,两者是“技术原理”和“应用方式”的关系。
具体来说,事件委托通过将子元素的事件处理函数绑定到父元素上,利用事件冒泡的特性,当子元素触发事件时,事件会冒泡到父元素,由父元素的处理函数统一处理。
优点包括:
- 减少事件绑定次数,节省内存(尤其是列表等动态元素)
- 新增子元素自动拥有事件处理,无需重新绑定
- 简化代码结构,便于维护
实现示例:
// 给ul绑定一次事件,处理所有li的点击
document.querySelector('ul').addEventListener('click', function(e) {
// 通过e.target判断是否点击了li
if (e.target.tagName === 'LI') {
console.log('点击了li:' + e.target.textContent);
}
});
这里的关键就是事件冒泡——li的点击事件能冒泡到ul,否则事件委托无法实现。但要注意,如果在子元素中阻止了冒泡(e.stopPropagation()
),事件委托就会失效。
扩展思考2:stopPropagation()
和stopImmediatePropagation()
有什么区别?
两者都能阻止事件冒泡,但stopImmediatePropagation()
更“狠”:
stopPropagation()
:只阻止事件向上冒泡,不影响当前元素的其他事件处理函数stopImmediatePropagation()
:不仅阻止冒泡,还会阻止当前元素后续绑定的同类型事件处理函数
示例:
const btn = document.getElementById('btn');
// 第一个点击事件处理函数
btn.addEventListener('click', function(e) {
console.log('第一个处理函数');
// e.stopPropagation(); // 只阻止冒泡,第二个处理函数会执行
e.stopImmediatePropagation(); // 阻止冒泡+阻止后续处理函数
});
// 第二个点击事件处理函数
btn.addEventListener('click', function() {
console.log('第二个处理函数'); // 如果用了stopImmediatePropagation,这里不会执行
});
// 父元素的点击事件
document.body.addEventListener('click', function() {
console.log('body的处理函数'); // 如果阻止了冒泡,这里不会执行
});
使用场景:当需要严格控制事件处理顺序,或防止其他脚本干扰时,用stopImmediatePropagation()
;普通阻止冒泡用stopPropagation()
即可。
扩展思考3:为什么有时候preventDefault()
会失效?
preventDefault()
失效通常有以下几种原因:
- 事件不可取消:某些事件的
cancelable
属性为false
(不可取消),如load
、scroll
事件,调用preventDefault()
无效。
window.addEventListener('scroll', function(e) {
e.preventDefault(); // 无效,scroll事件不可取消
});
-
调用时机错误:在事件捕获阶段调用
preventDefault()
可能对某些冒泡阶段的默认行为无效,应在目标阶段或冒泡阶段调用。 -
事件对象错误:未正确传递事件对象,或参数名不匹配(如函数参数用
e
,但实际传的是event
)。
// 错误示例:参数名不匹配
btn.addEventListener('click', function(event) {
e.preventDefault(); // 报错:e is undefined
});
- 第三方库冲突:某些库可能会重写事件处理机制,导致
preventDefault()
被覆盖或失效。
解决方法:
- 用
event.cancelable
检查事件是否可取消 - 确保事件对象正确传递和引用
- 在事件处理函数开头调用
preventDefault()
- 必要时使用
return false
(仅限DOM0级事件)
扩展思考4:移动端触摸事件的冒泡和默认行为有哪些特殊之处?
移动端的touch
事件(touchstart
、touchmove
、touchend
)也存在冒泡和默认行为,但有特殊之处:
-
触摸事件的冒泡:
- 和点击事件一样会冒泡,可用
stopPropagation()
阻止 - 但触摸事件的传播速度更快,可能引发更复杂的交互冲突(如滑动和点击的冲突)
- 和点击事件一样会冒泡,可用
-
需要特别处理的默认行为:
- 页面滚动(
touchmove
会触发) - 缩放(双指触摸)
- 长按选中文字
- 链接和表单元素的默认行为
- 页面滚动(
-
常用解决方案:
- 阻止页面滚动:在
touchmove
中调用preventDefault()
document.addEventListener('touchmove', function(e) { e.preventDefault(); // 阻止页面滚动 }, { passive: false }); // 注意passive选项
-
处理滑动冲突:通过触摸位置计算判断是滑动还是点击,再决定是否阻止冒泡
-
passive
选项:现代浏览器中,touchmove
和wheel
事件默认启用passive: true
,此时preventDefault()
会失效并报警告,需显式设置passive: false
- 阻止页面滚动:在
-
300ms延迟问题:移动端点击事件有300ms延迟(为判断双击缩放),解决方法包括:
- 使用
<meta name="viewport" content="width=device-width">
- 用
touch
事件替代click
- 使用
FastClick
库
- 使用
移动端事件处理更复杂,需要平衡用户体验和自定义需求,过度阻止默认行为可能导致页面失去基本交互能力(如无法滚动)。
结尾
事件冒泡和默认行为就像前端开发中的“隐形之手”,看不见摸不着,却时刻影响着用户交互。掌握了stopPropagation()
和preventDefault()
这两个“遥控器”,你就能从被动应对变成主动掌控。
回想一下,你是不是也遇到过这些场景:
- 点击弹窗按钮却触发了关闭逻辑
- 下拉菜单展开时,点击其他地方没反应
- 移动端滑动列表时,页面总是跟着滚动
这些问题的根源都是没处理好事件的传播和默认行为。现在再遇到类似问题,你应该能快速定位原因,用今天学到的方法轻松解决。
最后送大家一句口诀:“冒泡传播像涟漪,stopPropagation来隔离;默认行为别任性,preventDefault管到底;事件对象要抓牢,参数名称别错记;兼容处理不能少,交互流畅才满意。” 希望这句口诀能帮你记住今天的知识点!