版本信息
| 作者 | 时间 | 主要变更内容 | 链接 | 
|---|---|---|---|
| 吴惟刚 | 2022/02/25 | 事件代理 | http://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                                
                                :下一篇 »