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>
网景公司提出的事件流叫事件捕获流。事件捕获流的思想是外层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添加的事件监听必须通过removeEventListener并传入与添加时相同的参数来移除。也就意味着通过addEventListener添加的匿名函数无法移除!
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
事件修饰符改为捕获。
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>
总结:通过上面代码我们知道了事件对象+冒泡机制可以实现事件委托。事件委托就是当事件触发时,通过事件冒泡(或事件捕获)把要做的事委托给父元素来处理。