<div class="爷爷">
<div class="爸爸">
<div class="儿子">
文字
</div>
</div>
</div>
给三个div分别添加事件监听fnYe/fnBa/fnEr
问:上述代码,点击文字,算点击了谁
答:都算
调用顺序:
- 首先从外向内按爷爷=>爸爸=>儿子顺序看有没有函数监听
- 然后从内向外按儿子=>爸爸=>爷爷顺序看有没有函数监听
- 事件捕获:从外向内找监听函数,叫事件捕获
- 事件冒泡:从内向外找监听函数,叫事件冒泡
- 如果事件函数放在捕获阶段,则函数在捕获阶段会被找到然后调用
- 如果事件函数放在冒泡阶段,则经历捕获阶段时没有找到事件函数,然后开始冒泡阶段,在这个阶段事件函数被找到,最后调用
特例:监听元素===操作元素的事件调用顺序:哪个事件在先,哪个事件就先被监听
添加事件的方法:
target.addEventListener(‘click’,fn,bool)
如果bool不传或为fasly就将事件函数放置在冒泡阶段
如果bool为true,就将事件函数放置在捕获阶段
target 和 currentTarget 的区别
- e.target:是用户操作的元素(触发事件元素)
- e.currentTarget是程序员监听的元素 (绑定事件元素)
打断冒泡过程
函数:e.stopPropagation()
但有的事件比较特殊,不能取消。如:scroll
禁止页面滚动
1、阻止滚轮效果
x.addEventListener(“wheel”,(e)=>{
e.preventDefault()
})
2、阻止触屏效果
x.addEventListener(“touchstartl”,(e)=>{
e.preventDefault()
})
3、除去页面滚动条(css处添加)
::-webkit-scrollbar {
width : 0 !important
}
自定义事件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div id=div1>
<button id=button1>点击触发 Bruce 事件
</button>
</div>
</body>
</html>
button1.addEventListener('click', ()=>{
const event = new CustomEvent("Bruce", {"detail":{name:'Bruce', age: 18}})
button1.dispatchEvent(event)
})
button1.addEventListener('Bruce', (e)=>{
console.log('Bruce')
console.log(e.detail)
})
事件委托:
场景一:
需要给100个按钮添加点击事件,咋办?
答: 监听这100个按钮的祖先,等冒泡的时候判断target是不是这100个按钮中的一个
场景二:
需要监听当前还不存在的元素的点击事件,咋办?
答:监听祖先即可,等冒泡的时候判断target是不是想要监听的元素即可
事件委托的优点:
- 省监听数(内存)
- 可以监听动态元素
封装事件委托:
要求:写出一个函数on(‘click’,’#testDiv’,’button’,fn),当用户点击#testDiv里的button元素时,调用fn函数,要求用到事件委托
答案: 通过递归判断e.target的祖先是否有button元素,且li元素依旧是在#testDiv里面的
const delegate = function(eventType,element,selector,fn){
element.addEventListener(eventType,e=>{
let el = e.target
while(!el.matches(selector)){
if(element===el){
el = null
break
}
el = el.parentNode
}
el&&fn.call(el,e,el)
})
return element
}
注:这里讲到事件是DOM事件,是DOM的功能,而不是JS的功能,JS只是调用了DOM提供的addEventListener而已。