事件机制
事件捕获和事件冒泡
- 事件捕获:网景的事件流叫做事件捕获,从外向内,找监听函数
- 事件冒泡:IE的事件流叫做事件冒泡,从内向外,找监听函数
捕获机制示意图
事件绑定API
- IE 5*: baba.attachEvent(‘onclick’, fn)//冒泡
- 网景: baba.addEventListener( ‘click’, fn)//捕获
- W3C: baba.addEventListener(‘click’, fn, bool) 注:
- 如果bool不传或为falsy,就让fn走冒泡,即当浏览器在冒泡阶段发现baba有fn 监听函数,就会调用fn,并提供事件信息。
- 如果bool为true,就让fn走捕获,即当浏览器在捕获阶段发现 baba有fn 监听函数,就会调用fn ,并提供事件信息
取消冒泡
捕获不可取消,但是冒泡可取消
e.stopPropagation()可中断冒泡,浏览器不在向上走;
不可阻止默认动作
- 有些事件不能阻止默认动作
- MDN搜索scroll event,看到Bubbles和 Cancelable
- Bubbles的意思是该事件是否冒泡,所有冒泡都可取消
- Cancelable的意思是开发者是否可以阻止默认事件
- Cancelable与冒泡无关
- 推荐看MDN英文版,中文版内容不全
- 如何阻止滚动 scroll 事件不可阻止默认动作
- 阻止scroll默认动作没用,因先有滚动才有滚动事件
- 要阻止滚动,可阻止 wheel和 touchstart的默认动作
- 注意你需要找准滚动条所在的元素,示例
- 但是滚动条还能用,可用CSS让滚动条
width: 0 (::-webkit-scrollbar { width: 0 !important })
- CSS也行 使用overflow: hidden可以直接取消滚动条
事件委托
事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
事件委托:不监听元素自身,而是监听其祖先元素,然后判断e.target是不是该元素(或该元素的子元素)
优点:
- 省监听数,减少内存消耗
<div id="div1">
<button>click 1</button>
<button>click 2</button>
<button>click 3</button>
<button>click 4</button>
<button>click 5</button>
</div>
<script>
div1.addEventListener('click',(e)=>{
//用t保存目标元素,否则e会消失
const t = e.target
if(t.tagName.toLowerCase() === 'button'){
console.log('button内容是:' + t.textContent)
}
})
</script>
- 可以监听动态元素(暂时不存在的元素)
<div id="div1">
</div>
<script>
setTimeout(()=>{
//div1里面添加一个button
const button = document.creatElement('button')
button.textContent = 'click 1'
div1.appendChild(button)
},1000) //产生一个button,button内容,把button放到div1里面
div1.addEventListener('click',(e)=>{
const t=e.target//把t记为被用户操作的元素
if (t.tagName.toLowerCase() ==='button'){
console.log('button被click')
}
});
</script>
- 封装事件委托
<div id="div1">
</div>
<script>
setTimeout(()=>{
const button = document.creatElement('button')
button.textContent = 'click 1'
div1.appendChild(button)
},1000)
on('click','#div1','button',()=>{
console.log('button被点击了')
})
function on(eventType, element, selector, fn){
//判断如果element不是元素
if(!(element instanceof Element)){
element = document.querySelector(element)
}
element.addEventListener(eventType,(e)=>{
const t = e.target
if(t.matches(selector)){//matches用来判断一个元素是否满足选择器
fn(e)
}
})
}