版本信息
作者 | 时间 | 主要变更内容 | 链接 |
---|---|---|---|
吴惟刚 | 2022/02/25 | 事件代理 | http://www.wuweigang.com/?id=365 |
概述
事件代理对前端来说非常常见,尤其是jquery时代,我们为了提升性能,我们会尽量减少给每个元素绑定事件,而是给需要绑定事件的元素的父级绑定事件。
原理
将事件绑定在父级元素上, 通过判断event.target对象,判断当前点击的元素是否是目标元素或者是目标元素的后代元素,决定是否触发事件回调函数。
示例
分三段,html,css,js, 大家可以复制代码进行浏览器中测试。
operateProxyEvent() 函数,大家可以参考
html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<html lang="en">
<head>
<meta charset="UTF-8">
<title>原生事件代理的实现</title>
<link rel="stylesheet" href="./index.css">
</head>
<body>
<h1>原生事件代理的实现</h1>
<div class="fd-proxy-contain" id="jsProxyContain">
<ul>
<li class="jsItem" data-number="1">
<h3>条目一标题</h3>
<p><span>条目一内容</span></p>
</li>
<li class="jsItem" data-number="2">
<h3>条目二标题</h3>
<p><span>条目二内容</span></p>
</li>
<li class="jsItem" data-number="3">
<h3>条目三标题</h3>
<p><span>条目三内容</span></p>
</li>
</ul>
<div>
<p>这里不是目标节点</p>
<p>这里不是目标节点</p>
<p>这里不是目标节点</p>
<p>这里不是目标节点</p>
<p>这里不是目标节点</p>
</div>
</div>
<script src="./index.js"></script>
</body>
</html>
css
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
ul, li {
list-style: none;
}
li, .fd-proxy-contain > div > p {
padding: 20px;
font: 16px/1.5em "Microsoft YaHei";
border-bottom: 1px solid #ccc;
}
.fd-proxy-contain > div > p:last-child{
border: none;
}
h1 {
line-height: 3em;
text-align: center;
}
.fd-proxy-contain {
display: flex;
flex-flow: row nowrap;
margin: 0 auto;
width: 800px;
border: 1px solid #ccc;
}
.fd-proxy-contain > ul {
flex: 200px 0 0;
border-right: 1px solid #ccc;
}
.fd-proxy-contain > div {
flex: auto 1 1;
}
js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52/**
* @author wuwg
* @createTime 20220225
* @param event {Object} event 事件
* @param proxyContain {Object} 代理容器元素
* @param callback {function} 找到目标元素后的回调函数
*/
// 处理代理事件
function operateProxyEvent(event, proxyContain, callback) {
// 代理容器
const _proxyContain = proxyContain;
// 是否继续查找
let _loopFlag = false;
// 【当前节点】
let _currentNode = event.target;
// 【目标节点】
let _targetNode = null;
// 循环查找目标元素
do {
// 判断 【当前节点】是不是【目标节点】
const _isTargetFlag = _currentNode &&
// 这里判断的是class 为 item
_currentNode.classList.contains('jsItem');
if (_isTargetFlag) {
// 打断循环
_loopFlag = false;
// 【目标节点】= 【当前节点】
_targetNode = _currentNode;
}
// 是否继续循环, 找到目标,那么不再循环, 否则判断点击元素是否在代理容器里,在的话继续循环查找。
_loopFlag = _isTargetFlag ? false : _proxyContain.contains(_currentNode);
// 【当前节点】往上推一级,等于当前节点的【父节点】
_currentNode = _loopFlag ? _currentNode.parentNode : _currentNode;
} while (_loopFlag);
// 如果是目标节点
if (_targetNode) {
typeof callback === 'function' && callback(_targetNode);
} else {
console.warn('非代理的目标节点: 不触发点击事件');
}
}
// 代理容器
const _proxyContain = document.querySelector('#jsProxyContain');
// 给代理容器绑定事件
_proxyContain.addEventListener('click', (event) => {
// 处理代理事件
operateProxyEvent(event, _proxyContain, (target) => {
const _dataItemNumber = target.dataset.number;
alert('是代理的目标节点,当前节点的number值是:' + _dataItemNumber);
});
});
视图
左侧列表会触发事件,右侧列表不会触发事件!
-
« 上一篇:
经验谈-排查问题思路
-
百度地图API
:下一篇 »