场景:一个页面中的导航栏/图片下拉框,具有多个相同的标签节点,可以获取点击的某一个,并封装对应的方法函数(不考虑IE)
需要考虑的步骤:
(1)事件代理的原理(事件冒泡)
(2)函数中需要考虑的几点(默认行为,this指向)
1.事件捕获和事件冒泡
DOM是一种树形结构,事件会在元素结点和根结点之间传递,途经的结点会收到该事件,传递过程可以称为事件流。
事件流分为三个阶段:
- 捕获阶段
- 目标阶段
- 冒泡阶段
事件冒泡会从当前触发的事件目标一级一级往上传递,依次触发,直到document为止。
事件捕获会从document开始触发,一级一级往下传递,依次触发,直到真正事件目标为止。
window->document->HTML->body->父元素->子元素
2.事件代理
(1)原理:事件冒泡机制。当子结点触发事件时,事件流会向父节点传播,并触发父节点上的事件。
(2)优点:
- 代码简洁,当动态增加结点时,无需做额外操作
- 减少绑定注册事件,减少浏览器内存消耗
3.函数实现
(1)实现一次事件冒泡
<div id="para">
<ul id="contain">
<li id="p1">标签1</li>
<li id="p2">标签2</li>
<li id="p3">标签3</li>
</ul>
</div>
/*
*
* 事件冒泡
*
*/
function bindEvent(elem, type, fn) {
elem.addEventListener(type, fn);
}
var paras = document.getElementById('para')
var contains = document.getElementById('contain')
var p1s = document.getElementById('p1')
console.log(paras, contains, p1s)
bindEvent(p1s, 'click', function(e) {
e.preventDefault()
//阻止事件冒泡 e.stopPropagation() e.cancelBubble = true IE
console.log('p')
})
bindEvent(paras, 'click', function(e) {
console.log('para')
})
可以看到,当点击标签的时候,结点的父元素也触发了对应的方法。
(2)实现事件代理
/*
*
* 事件代理
*
*/
function eventProxy(elem, type, proxyElem, fn) {
if(fn === null) { // 不使用事件代理
fn = proxyElem;
proxyElem = null;
}
elem.addEventListener(type, function(e) {
var target;
if(proxyElem) { // 使用事件代理的情况
target = e.target;
console.log(target)
if (target.matches(proxyElem)) {
fn.call(target, e); // 改变函数this执行上下文到目标结点
}
} else { // 不使用事件代理的情况
fn(e);
}
})
}
var proxyContainer = document.getElementById('proxy');
eventProxy(proxyContainer, 'click', 'a' , function(e) {
e.preventDefault();
console.log(this.innerHTML); // 获取当前结点信息
})
可以看到,通过事件代理的方式,将事件绑定在父节点上,并可以区分被点击分子节点的信息。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。