事件委托是利用事件冒泡原理,让节点的父级代为执行事件。而不需要循环遍历元素的子节点
·优点
√ 省监听数(内存)
√ 可以监听动态元素
·场景一
你要给100个按钮添加点击事件,咋办?
答:监听这100个按钮的父级,等冒泡的时候判断event.target的值是不是这100个按钮中的一个
·场景二
你要监听目前不存在的元素的点击事件,咋办?
答:监听父级,等点击的时候看看是不是要监听的元素即可
下面使用函数进行封装的一段代码,使用envent.target判断是否匹配目标选择器,示例:
<html>
<head>
<meta charset="utf-8">
<title>title</title>
</head>
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script>
on('click','ul','li',()=>{
console.log('li 被点击了')
})
function on(eventType,element,selector,fn){
if(!(element instanceof Element)){
//if判断参数传入的element是否为Element元素,如果是ID名或类名则进行获取对应名称的元素
element=document.querySelector(element)
}
element.addEventListener(eventType,(e)=>{
const t=e.target
if(t.matches(selector)){ // maches判断选择器是否匹配
return fn(e)
}
})
}
</script>
</body>
</html>
·场景三
上述场景二存在问题:li里面存在span元素,点击span元素不是当前监听的目标li元素,不会触发函数。
解决:那么这样的话应该遍历父节点是否存在li元素,直到遍历到ul为止。 示例:
<html>
<head>
<meta charset="utf-8">
<title>title</title>
</head>
<body>
<ul>
<li>1</li>
<li><span>2</span></li>
<li>3</li>
</ul>
<script>
function on(eventType,element,selector,fn){
element.addEventListener(eventType,e=>{
let el=e.target
// maches判断选择器是否匹配
while(!el.matches(selector)){
//如果一直遍历父元素到事件委托的元素为止则证明没有目标元素
if(el===element){
el=null //让el为空结束循环
break
}
el=el.parentNode
}
//el不为空执行fn
el&&fn.call(el,e,el)
})
return element
}
on('click','ul','li',(e)=>{console.log(e.target.innerHTML)})
</script>
</body>
</html>