JavaScript与HTML的交互是通过事件实现的,事件代表文档流或浏览器窗口中某个有意义的时刻。
而事件流代表了页面接收事件的顺序,结果IE和Netscape开发团队提出了几乎完全相反的事件流方案,IE将支持事件冒泡流,而Netscape将支持事件捕获流。
事件冒泡
IE提出的事件流叫做事件冒泡,即事件开始时由最具体的元素接收,然后逐级向上传播,看一下以下示例:
<body onclick="bodyclick( )">
<div onclick="divclick( )">
<button onclick="buttonclick( )">
</button>
</div>
</body>
<script>
function bodyclick(){
console.log('body被点击')
}
function divclick(){
console.log('div被点击')
}
function buttonclick(){
console.log('button被点击')
}
</script>
点击页面上的button:

事件捕获
网景公司提出的事件流叫事件捕获流。事件捕获流的思想是外层DOM节点应该更早接收到事件,而最具体的节点应该最后接收到事件,针对上面同样的例子,点击按钮,那么此时click事件会按照这样传播:(下面我们就借用addEventListener的第三个参数来模拟事件捕获流)
<body>
<div><button>点击捕获</button></div
</body>
<script>
var body=documemt.querySelector('body')
var div=documemt.querySelector('div')
var button=documemt.querySelector('button')
body.addEventListener('click',function(){console.log('body被点击')},true)
div.addEventListener('click',function(){console.log('div被点击')},true)
button.addEventListener('click',function(){console.log('button被点击')},true)
</script>
打印出来的结果是:

addEventListener( type, listener, useCapture )简单分析
- type: 事件类型
- listener: 事件监听处理函数
- useCapture: 设置事件查找方式
false: 冒泡事件(默认值)
true: 捕获事件
注意:通过addEventListener添加的事件监听必须通过removeEventListener并传入与添加时相同的参数来移除。也就意味着通过addEventListener添加的匿名函数无法移除!
vue中的@click
vue 中@click是默认的冒泡行为,当点击button时,虽然事件流是先捕获后冒泡,当捕获先经过 div时,divClick不触发,所以btnClick先触发,开始冒泡流程到div时,divClick才触发。
<div @click = "divClick">
<button @click="btnClick">点击</button>
</div>
<script>
var vm = new vue ({
el:"#app",
data: {},
methods: {
divClick() {
console.log("divClick")
},
btnClick() {
console.log("btnClick")
}
}
})
</script>
// btnClick
// divClick
vue通过@click.capture事件修饰符改为捕获。
react中的onClick
export class LoginPage extends Component {
onClickInner(e) {
console.log('inner a')
}
onClickOuter(e) {
console.log('outer div')
}
render() {
return (
<div onClick={this.onClickOuter}>
<a onClick={this.onClickInner}>inner a</a>
</div>
)
}
}
React中的onClick是冒泡点击事件,同样,使用onClickCapture为dom绑定捕获的点击事件。
事件代理机制(事件委托)
利用事件冒泡完成事件代理机制:
<ul>
<li>列表1</li>
<li>列表2</li>
</ul>
当我们要给如上列表中的li都绑定一个点击事件点击获取li中的内容,一般是利用for遍历元素绑定点击事件。假如我们有1w个 li 节点,使用如上方式就需要绑定1w个事件,这样操非常影响代码性能。
此时,我们可以利用冒泡机制来解决如上的问题,就是将事件绑定到父元素身上 ul 身上。
<body>
<ul>
<li>列表1</li>
<li>列表2</li>
</ul>
<script>
let ul = document.querySelector('ul');
//我们可以通过事件对象(e)中的target属性可以访问到事件源(也就事件的触发元素)
ul.addEventListener('click',function(e){
console.log(e.target.innerHTML);
},false);
</script>
</body>
总结:通过上面代码我们知道了事件对象+冒泡机制可以实现事件委托。事件委托就是当事件触发时,通过事件冒泡(或事件捕获)把要做的事委托给父元素来处理。
本文详细介绍了JavaScript中的事件冒泡、事件捕获以及这两种事件流的工作原理。通过示例和代码解释了addEventListener的事件监听设置,并讨论了在Vue和React中如何处理事件。同时,文章探讨了事件代理机制,展示了如何利用事件冒泡提高代码性能,减少事件绑定数量。

861

被折叠的 条评论
为什么被折叠?



