目录
事件流
// 事件流指的是事件完整执行过程中的流动路径
// 说明:假设页面里有个div,当触发事件时,会经历两个阶段,分别是捕获阶段、冒泡阶段
// 简单来说:
// 捕获阶段是 从父到子
// 冒泡阶段是从子到父
1.事件捕获和事件冒泡
// 🏆事件捕获
// 事件捕获概念:(相同事件)
// 从DOM的根元素开始去执行对应的事件(从外到里)
// 事件捕获需要写对应代码才能看到效果
// 代码:
// 事件源.addEventListener(事件,函数,是否捕获)
<!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>Document</title>
<style>
.father {
width: 300px;
height: 300px;
background-color: #000;
margin: 100px auto;
display: flex;
justify-content: center;
align-items: center;
}
.son {
width: 100px;
height: 100px;
background-color: #f00;
}
</style>
</head>
<body>
<div class="father">
<div class="son">
</div>
</div>
<script>
// 🏆事件捕获
// 事件捕获概念:(相同事件)
// 从DOM的根元素开始去执行对应的事件(从外到里)
// 事件捕获需要写对应代码才能看到效果
// 代码:
// 事件源.addEventListener(事件,函数,是否捕获)
document.addEventListener('click', function () {
console.log('我是爷')
},true)
document.querySelector('.father').addEventListener('click', function () {
console.log('我是爹')
},true)
document.querySelector('.son').addEventListener('click', function () {
console.log('我是儿')
},true)
</script>
</body>
</html>

// 说明:
// addEventListener第三个参数传入true代表是捕获阶段触发(很少使用)
// 若传入false代表冒泡阶段触发,默认就是false
// 若是用 L0 事件监听,则只有冒泡阶段,没有捕获
// 🏆事件冒泡
// 事件冒泡概念:
// 当一个元素的事件被触发时,同样的事件将会在该元素的所有祖先元素中依次被触发。这一过程被称为事件冒泡
// 简单理解:当一个元素触发事件后,会依次向上调用所有父级元素的同名事件
// 事件冒泡是默认存在的
<!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>Document</title>
<style>
.father {
width: 300px;
height: 300px;
background-color: #000;
margin: 100px auto;
display: flex;
justify-content: center;
align-items: center;
}
.son {
width: 100px;
height: 100px;
background-color: #f00;
}
</style>
</head>
<body>
<div class="father">
<div class="son">
</div>
</div>
<script>
document.addEventListener('click', function () {
console.log('我是爷')
})
document.querySelector('.father').addEventListener('click', function () {
console.log('我是爹')
})
document.querySelector('.son').addEventListener('click', function () {
console.log('我是儿')
})
</script>
</body>
</html>

2. 阻止事件流动
//🏆 阻止事件流动
// 因为默认就有冒泡模式的存在,所以容易导致事件影响到父级元素
// 若想把事件就限制在当前元素内,就需要阻止事件流动
// 阻止事件流动需要拿到事件对象
// 语法:
// 事件对象.stopPropagation()
// 此方法可以阻断事件流动传播,不光在冒泡阶段有效,捕获阶段也有效
<!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>Document</title>
<style>
.father {
width: 300px;
height: 300px;
background-color: #000;
margin: 100px auto;
overflow: hidden;
}
.son {
width: 100px;
height: 100px;
background-color: #f00;
margin: 100px auto;
}
</style>
</head>
<body>
<div class="father">
<div class="son">
<a href="www.baidu.com">百度一下</a>
<form action="index.js">
<input type="text">
<input type="submit" value="提交">
</form>
</div>
<script>
//🏆 阻止事件流动
// 因为默认就有冒泡模式的存在,所以容易导致事件影响到父级元素
// 若想把事件就限制在当前元素内,就需要阻止事件流动
// 阻止事件流动需要拿到事件对象
// 语法:
// 事件对象.stopPropagation()
// 此方法可以阻断事件流动传播,不光在冒泡阶段有效,捕获阶段也有效
document.addEventListener('click', function () {
console.log('我是爷')
})
document.querySelector('.father').addEventListener('click', function () {
console.log('我是爹')
})
document.querySelector('.son').addEventListener('click', function (e) {
console.log('我是儿子')
e.stopPropagation()//实现点击儿子,只弹出儿子,不弹出爹和爷//阻止传播
})
</script>
</body>
</html>

3.🏆 两种注册事件的区别
// 🏆 两种注册事件的区别:
// 💎传统on注册(L0)
// 同一个对象,后面注册的事件会覆盖前面注册(同一个事件)
// 直接使用null覆盖偶就可以实现事件的解绑
// 都是冒泡阶段执行的
// 💎事件监听注册(L2)
// 语法: addEventListener(事件类型, 事件处理函数, 是否使用捕获)
// 后面注册的事件不会覆盖前面注册的事件(同一个事件)
// 可以通过第三个参数去确定是在冒泡或者捕获阶段执行
// 必须使用removeEventListener(事件类型, 事件处理函数, 获取捕获或者冒泡阶段)
// 匿名函数无法被解绑
<!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>Document</title>
</head>
<body>
<button>点击</button>
<script>
let btn = document.querySelector('button')
btn.onclick = function () {
console.log('1');
}
btn.onclick = function () {
console.log('2');
}
同一对象同一事件,on来注册后面的会覆盖前面的
</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>Document</title>
</head>
<body>
<button>点击</button>
<script>
btn.addEventListener('click',
function () {
console.log('1');
})
btn.addEventListener('click',
function () {
console.log('2');
})
//用addEventListener后面注册的事件不会覆盖前面注册的事件(同一个事件)
</script>
</body>
</html>

4. 解绑事件
// 🏆on注册解绑
语法:DOM对象.on事件类型 = null
<!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>Document</title>
</head>
<body>
<button>点击</button>
<script>
let btn = document.querySelector('button')
// 解绑事件
// 🏆on注册解绑
btn.onclick = function () {
console.log('on监听我被点击了');
}
btn.onclick = null
</script>
</body>
</html>
// 🏆addEventListener注册解绑
// 1.注册事件采用的 addEventLinstener(‘事件类型',函数名)想要解绑事件的处理函数不能采用匿名函数只能使用具名函数(有名字的函数)
// 2.需要解绑使用事件源.removeEventListener('事件类型',函数名)
<!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>Document</title>
</head>
<body>
<button>点击</button>
<script>
let btn = document.querySelector('button')
// 1.注册事件采用的 addEventLinstener(‘事件类型',函数名)想要解绑事件的处理函数不能采用匿名函数只能使用具名函数(有名字的函数)
// 2.需要解绑使用事件源.removeEventListener('事件类型',函数名)
function fn() {
console.log('addEventListener我被点击了');
}
btn.addEventListener('click', fn)
btn.removeEventListener('click', fn)
</script>
</body>
</html>
5.鼠标经过的两种写法的区别
// mouseover和mouseout会有冒泡效果
<!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>Document</title>
<style>
.father {
width: 300px;
height: 300px;
background-color: #000;
margin: 100px auto;
display: flex;
justify-content: center;
align-items: center;
}
.son {
width: 100px;
height: 100px;
background-color: #f00;
}
</style>
</head>
<body>
<div class="father">
<div class="son">
</div>
</div>
<script>
// mouseover和mouseout会有冒泡效果
document.querySelector('.father').addEventListener('mouseover', function () {
console.log('我是爹')
})
document.querySelector('.son').addEventListener('mouseover', function () {
console.log('我是儿')
})
</script>
</body>
</html>

// mouseenter和mouseleave 没有冒泡效果
<!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>Document</title>
<style>
.father {
width: 300px;
height: 300px;
background-color: #000;
margin: 100px auto;
display: flex;
justify-content: center;
align-items: center;
}
.son {
width: 100px;
height: 100px;
background-color: #f00;
}
</style>
</head>
<body>
<div class="father">
<div class="son">
</div>
</div>
<script>
// mouseenter和mouseleave 没有冒泡效果
document.querySelector('.father').addEventListener('mouseenter', function () {
console.log('我是爹')
})
document.querySelector('.son').addEventListener('mouseenter', function () {
console.log('我是儿')
})
</script>
</body>
</html>

6.🏆阻止默认行为方法
// 🏆阻止默认行为方法
// 事件对象.preventDefault()
注意是给form表单注册事件而不是提交按
<!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>Document</title>
<style>
.father {
width: 300px;
height: 300px;
background-color: #000;
margin: 100px auto;
overflow: hidden;
}
.son {
width: 100px;
height: 100px;
background-color: #f00;
margin: 100px auto;
}
</style>
</head>
<body>
<div class="father">
<div class="son">
<a href="www.baidu.com">百度一下</a>
<form action="index.js">
<input type="text">
<input type="submit" value="提交">
</form>
</div>
<script>
// 🏆阻止默认行为方法
// 事件对象.preventDefault()
document.querySelector('a').addEventListener('click', function (e) {
e.preventDefault()
})
// 阻止表单提交
// 注意是给form表单注册事件而不是提交按钮
document.querySelector('form').addEventListener('submit', function (e) {
alert('确认提交吗?')
e.preventDefault()
})
</script>
</body>
</html>

事件委托
// 🏆事件委托是利用事件流的特征解决一些开发需求的知识技巧
// 总结:
// 优点:给父级元素加事件(可以提高性能)
// 原理:事件委托其实是利用事件冒泡的特点, 给父元素添加事件,子元素可以触发
// 实现:事件对象.target 可以获得真正触发事件的元素
<!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>Document</title>
<style>
li {
border: 1px solid #000;
}
</style>
</head>
<body>
<ul>
<li> 第1个li</li>
<li> 第2个li</li>
<li> 第3个li</li>
<li> 第4个li</li>
<li> 第5个li</li>
<li> 第6个li</li>
<li> 第7个li</li>
<li> 第8个li</li>
</ul>
<script>
// 🏆事件委托是利用事件流的特征解决一些开发需求的知识技巧
// 总结:
// 优点:给父级元素加事件(可以提高性能)
// 原理:事件委托其实是利用事件冒泡的特点, 给父元素添加事件,子元素可以触发
// 实现:事件对象.target 可以获得真正触发事件的元素
// 不要给每个li注册事件,给ul父亲添加事件
document.querySelector('ul').addEventListener('click', function (e) {
// 得到当前元素
// 打印触发事件对象的标签名
if (e.target.tagName === 'LI') {
console.log(`${e.target.innerHTML}被点击了`);
e.target.style.color = '#f00'
}
// 给点击的li改变颜色
})
</script>
</body>
</html>

自定义属性
// h5:在标签里面 以data-XXX='' 自定义属性
//1. 获取dom对象
// 2.对象.dataset-XXX
<!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>Document</title>
</head>
<body>
<div class="box" data-name="你好"></div>
<script>
// 自定义属性
// h5:在标签里面 以data-XXX='' 自定义属性
//1. 获取dom对象
// 2.对象.dataset-XXX
const box = document.querySelector('.box')
console.log(box.dataset.name);
</script>
</body>
</html>