【20170204】JS事件委托
Closed this issue · 1 comments
zhongxia245 commented
时间:2016-12-03 15:20:07
问题
什么是事件委托?
一、事件冒泡
DOM2级 事件分为三个阶段(IE8以及之前不支持DOM事件流)
- 事件捕获
- 目标对象
- 冒泡
W3C模型:
页面上的点击事件流程是这样的, 从不准确节点 document,HTML开始一层一层的往下找,直到找到绑定目标事件的对象, 找到之后,事件会在一层一层的冒泡,冒泡到最顶层。
//第三个参数默认是 false, 标识事件触发在冒泡阶段
先执行目标事件处理函数,在处理父容器的事件。
如果为true的话, 先执行父容器的事件,在执行目标事件
addEventListener(eventname,fn,useCaptrue)
二、事件委托
把多个有相同事件处理函数的节点,把事件绑定到他们的父节点上。减轻对内存的损耗
- 根据事件冒泡的原理,衍生出委托事件
js事件委托,其实是使用了冒泡的原理,从点击的元素开始,递归方式的向父元素传播事件,这样做的好处是对于大量要处理的元素,不必为每个元素都绑定事件,只需要在他们的父元素上绑定一次即可,提高性能。 还有一个好处就是可以处理动态插入dom中的元素,直接绑定的方式是不行的。
就是事件目标自身不处理事件,而是把处理任务委托给其父元素或者祖先元素,甚至根元素事件委托很好地利用了"事件冒泡"。当点击子元素,根据"事件冒泡",该子元素的父级元素捕获了该次点击事件,并触发自己的方法。
1. 优点
- 提升性能【每个节点绑定事件,到把事件绑定到父容器上】
- 新增的元素还会有之前的处理事件
2. 缺点
- 不是所有的事件都能冒泡。 【focus, blur, load, unload】
- 在管理鼠标事件的时候,需要注意,因为鼠标事件太频繁了,如果鼠标事件处理有问题,就容易造成性能瓶颈
三、demo
<ul id="parent-list">
<li id="post-1">Post 1</li>
<li id="post-2">Post 2</li>
<li id="post-3">Post 3</li>
<li id="post-4">Post 4</li>
<li id="post-5">Post 5</li>
<li id="post-6">Post 6</li>
</ul>
给所有 li 绑定事件
- 写一个循环,给每一个 li 绑定上 click 事件
- 把事件绑定在ul 上, 通过 e.target 可以获取点击节点的信息
四、Jquery的事件委托
$(document).on(‘click‘,‘li‘,function(){
alert(‘这是一个li!!!‘);
});
用JS封装一个
/**
*/
function delegate(parent,selector,eventName,callback){
}
/**
* 事件委托
* @param {[type]} dom [绑定事件的DOM节点]
* @param {[type]} selector [需要绑定的子节点]
* @param {[type]} eventName [事件名称]
* @param {Function} callback [事件处理函数]
* @return {[type]} []
*/
function delegate(dom, selector, eventName, callback) {
if(dom){
dom.addEventListener(eventName,function(e){
e = e || window.event
if(e.target.tagName.toLowerCase() === selector){
callback && callback(e)
}
})
}
}
完整的事件委托方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件委托</title>
</head>
<body>
<ul id="id-ul">
<li>zhongxia1</li>
<li>zhongxia2</li>
<li>zhongxia3</li>
<li>zhongxia4</li>
</ul>
<button id="id-btn">添加一个li</button>
<script type="text/javascript">
var ul = document.querySelector('#id-ul')
delegate(ul, 'li', 'click', function(e) {
console.log(e.target)
})
addEvent(document.querySelector('#id-btn'), 'click', function() {
ul.innerHTML += '<li>动态添加的Item</li>'
})
/**
* 事件委托
* @param {[type]} dom [绑定事件的DOM节点]
* @param {[type]} selector [需要绑定的子节点]
* @param {[type]} eventName [事件名称]
* @param {Function} callback [事件处理函数]
* @return {[type]} []
*/
function delegate(dom, selector, eventName, callback) {
if (dom) {
addEvent(dom, eventName, function(e) {
e = e || window.event
if (e.target.tagName.toLowerCase() === selector) {
callback && callback(e)
}
},false)
}
}
function addEvent(elm, evType, fn, useCapture) {
if (elm.addEventListener) {
elm.addEventListener(evType, fn, !!useCapture); //DOM2.0
return true;
} else if (elm.attachEvent) {
var r = elm.attachEvent('on' + evType, fn); //IE5+
return r;
} else {
elm['on' + evType] = fn; //DOM 0
}
}
</script>
</body>
</html>
cji03 commented
delegate
方法中,if (e.target.tagName.toLowerCase() === 'li')
应该等于selector
吧,你这写死了。然后e.target
也应该hack一下。
addEvent
中useCapture
应该是Ture或者False吧。