目录
1.事件绑定和事件冒泡
事件绑定
event.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>事件 演示</title>
<style>
div {
border: 1px solid #ccc;
margin: 10px 0;
padding: 0 10px;
}
</style>
</head>
<body>
<button id="btn1">一个按钮</button>
<script src="./event.js"></script>
</body>
</html>
event.js
// 事件绑定函数
function bindEvent(elem, type, fn) {
elem.addEventListener(type, fn)
}
const btn1 = document.getElementById('btn1')
bindEvent(btn1, 'click', event=>{
console.log(event.target) // event.target就是触发点击的元素,这里就是btn1
event.preventDefault() // 阻止默认行为,如果这里是<a>标签,阻止默认跳转
alert('clicked')
})
运行结果
事件冒泡
事件冒泡的应用场景就是事件代理,我们后面再说
代码演示:
event.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>事件 演示</title>
<style>
div {
border: 1px solid #ccc;
margin: 10px 0;
padding: 0 10px;
}
</style>
</head>
<body>
<button id="btn1">一个按钮</button>
<div id="div1">
<p id="p1">激活</p>
<p id="p2">取消</p>
<p id="p3">取消</p>
<p id="p4">取消</p>
</div>
<div id="div2">
<p id="p5">取消</p>
<p id="p6">取消</p>
</div>
<script src="./event.js"></script>
</body>
</html>
event.js
// 事件绑定函数
function bindEvent(elem, type, fn) {
elem.addEventListener(type, fn)
}
const p1 = document.getElementById('p1')
bindEvent(p1, 'click', event => {
// event.stopPropagation() // 阻止冒泡
console.log('激活')
})
const body = document.body
bindEvent(body, 'click', event => {
console.log('取消')
// console.log(event.target)
})
event.stopPropagation() // 阻止冒泡,我们先把这一句注释掉看一下
运行结果
结果发现冒泡了,我点击激活的时候也触发了body的监听事件打印取消,该如何取消冒泡呢??
event.stopPropagation() // 阻止冒泡
取消上面event.js的这句注释,我们再来演示一下
这样就好了
2.事件代理
事件代理也叫事件委托,事件代理是基于事件冒泡的机制的
这篇文章写的事件代理的解释很通俗易懂:简述JS中的事件委托和事件代理
当不方便去一个一个循环绑定监听的时候就直接绑定它的父元素,最后再判断是不是想要的元素,再做其他的逻辑,这样的特点就是不用每个加监听,后续新增的子元素自动就有了父元素的监听,非常方便。
事件代理就会让代码看起来简洁,并且会减少浏览器的内存,毕竟每个元素加一个监听耗费内存,但是不要滥用,比如明明只有一个元素去监听,非要用事件代理就太勉强了
event.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>事件 演示</title>
<style>
div {
border: 1px solid #ccc;
margin: 10px 0;
padding: 0 10px;
}
</style>
</head>
<body>
<button id="btn1">一个按钮</button>
<div id="div3">
<a href="#">a1</a><br>
<a href="#">a2</a><br>
<a href="#">a3</a><br>
<a href="#">a4</a><br>
<button>加载更多...</button>
</div>
<script src="./event.js"></script>
</body>
</html>
event.js
// 通用的事件绑定函数,支持普通的监听和代理监听
function bindEvent(elem, type, selector, fn) {
if (fn == null) { // 三个参数和四个参数的判断处理
fn = selector;
selector = null;
}
elem.addEventListener(type, event=>{
const target = event.target;
if (selector) {
// 有selector就是代理
if (target.matches(selector)) {
fn.call(target, event);
}
} else {
fn.call(target, event);
}
});
}
// 普通绑定
const btn1 = document.getElementById('btn1')
bindEvent(btn1, 'click', event=>{
console.log(event.target)
alert('clicked') // 这里如果写this就不是和下面一样了,因为箭头函数this是父作用域的this,这里是window
})
// 代理绑定
const div3 = document.getElementById('div3')
bindEvent(div3, 'click', 'a', function (event) {
event.preventDefault()
alert(this.innerHTML) // 这里可以写this是因为bindEvent里面的fn.call(target, event),绑定了点击的target是<a>标签
})
// 如果是箭头函数
/*
bindEvent(div3, 'click', 'a', event=> {
event.preventDefault()
alert(event.target.innerHTML)
})
*/
运行结果
这里加载更多按钮没有添加逻辑,主要是为了告诉大家,这里如果再新增<a>标签,都会有绑定监听事件,因为父元素div绑定了监听,这也是事件的冒泡机制
这里的 button 和 a 都是绑定通用函数bindEvent,event.target是获取触发的元素,matches判断是否是触发元素
关注、留言,我们一起学习。
===============Talk is cheap, show me the code================