[TOC]
前端-捕获冒泡、代理、派发代码示例及封装
今天被实习生问到事件代理和派发的问题,举举例子讲了一番后,然后有了此文。
目录大纲
- 捕获冒泡示例
- 事件代理示例
- 事件派发示例
- 原理介绍:发布订阅者模式
- 事件派发,完整流程的封装(发布订阅者模式)
1. 捕获冒泡示例
事件监听api:addEventListener,有第三个参数,isCapture,意思是:是否捕获,默认false 冒泡
html部分
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件冒泡</title>
</head>
<body>
<div>
<p id="parEle">
我是父元素
<span id="sonEle">
---我是子元素---
</span>
</p>
</div>
</body>
</html>
script部分
- 测试例子1:(全冒泡,先子后父)(addEventListener第三个参数不写,默认冒泡)
```html
点击“—-我是子元素—-”,打印: 子级111 子级 父父父父父父级111111111 父父父父父父级
点击“我是父元素”,打印: 父父父父父父级111111111 父父父父父父级
2. 测试例子2:(全捕获,先父后子)(addEventListener第三个参数写 true) ```html <script type="text/javascript"> var sonEle = document.getElementById('sonEle'); var parEle = document.getElementById('parEle'); // 测试例子2:(全捕获,先父后子) parEle.addEventListener('click', function () { console.log('父父父父父父级111111111'); }, true); sonEle.addEventListener('click', function () { console.log('子级111'); }, true); parEle.addEventListener('click', function () { console.log('父父父父父父级'); }, true); sonEle.addEventListener('click', function () { console.log('子级'); }, true); </script> 点击“---我是子元素---”,打印: 父父父父父父级111111111 父父父父父父级 子级111 子级 点击“我是父元素”,打印: 父父父父父父级111111111 父父父父父父级
- 测试例子3:(前2个冒泡,后2个捕获)
```html
点击“—-我是子元素—-”,打印: 父父父父父父级 子级 子级111 父父父父父父级111111111
点击“我是父元素”,打印: 父父父父父父级 父父父父父父级111111111
<a name="128d0d23"></a> ## 2. 事件代理示例 好处:不用一个个绑定子元素事件了,直接绑父元素,然后用event.target来判断对应的子元素 ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>事件冒泡</title> </head> <body> //我们有一个div元素,它包含三个按钮: <div id="box"> <input type="button" value="按钮"> <input type="button" value="按钮2"> <input type="button" value="按钮3"> </div> <script> var box = document.getElementById('box'); // 好处: 不用一个个绑定子元素事件了 box.addEventListener('click', function(event) { console.log(1) if (event.target.tagName.toLowerCase() === 'input') { // some code console.log(event.target) } }); </script> </body> </html>
3. 事件派发示例
可以自定义事件new Event()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>派发事件</title> </head> <body> <div id="box">点我派发事件</div> <script> // 初始化事件 NBA var eventNBA = new Event("NBA", {"bubbles":true, "cancelable":false}); // 订阅者1 订阅NBA document.addEventListener('NBA', function (event) { console.log(7227) console.log(event) }, false); // 订阅者2 订阅NBA document.addEventListener('NBA', function (event) { console.log(234243223) console.log(event) }, false); document.getElementById('box').addEventListener('click', function(event) { document.dispatchEvent(eventNBA); // 事件派发:通知所有订阅了NBA的订阅者,触发他们的回调函数 }); </script> </body> </html>
1. 原理介绍:发布订阅者模式
可看我的另一篇: https://juejin.cn/post/6954250097651613733
2. 事件派发,完整流程的封装(发布订阅者模式)
class EventEmitter { constructor () { this._event = {} } on (dom, eventName, fn) { // 为dom绑定一个自定义event this._event[eventName] = new Event(eventName) dom.addEventListener(eventName, fn) } off (dom, eventName, fn) { // 为dom注销一个自定义event this._event[eventName] = null dom.removeEventListener(eventName, fn) } emit (dom, eventName) { // 事件派发 if (!this._event[eventName]) throw '不存在' + eventName dom.dispatchEvent(this._event[eventName]) } once (dom, eventName, fn) { // 事件派发一次 就注销 this.emit(dom, eventName) this.off(dom, eventName, fn) } } var myEmit = new EventEmitter() var fn = function (e) { console.log(e) } myEmit.on(document, 'okok', fn) myEmit.off(document, 'okok', fn) myEmit.once(document, 'okok', fn) myEmit.emit(document, 'okok')
- 测试例子3:(前2个冒泡,后2个捕获)
```html