JavaScript 事件代理需要注意的地方
我们知道,如果给form里面的button元素绑定事件,需要考虑它是否会触发form的submit行为。除此之外,其它场合给button元素绑定事件,你几乎不用担心这个事件会有什么非预期的附加效果,很自然地会这样写事件处理代码:
varbutton=document.querySelector('button') button.addEventListener('click',function(e){ console.log('点击了按钮') })
你之所以放心这么写,是因为这个button元素没有使用事件代理,即没有代理任何子元素的事件。
事件代理的意思是,你要为一个元素绑定事件,但你不是直接把事件绑定到这个元素自己身上,而是绑定到这个元素的父元素上。当子元素的某个事件(比如点击事件)触发时,它的父元素相同的事件也会触发(我们常说的事件冒泡),此时我们说父元素代理了子元素的事件。
举个例子,比如一个button元素中包含一个齿轮图标:
当用户点击齿轮图标,必然要触发click事件,但你并不会直接绑定事件到svg或use元素上,而是绑定到它们的父元素button上。即:
document.querySelector('button').addEventListener('click',function(e){ console.log('点击了按钮') })
这种情况,我们可以说,button元素代理了它的所有子元素的click事件。
但是,出现这种事件代理的情况时,我们就得小心了。
为了更直观地说明问题,我们把“父”元素上升到顶层的document元素:
document.documentElement.addEventListener('click',function(e){ console.log('我被点击了') })
只要网页中任意一个位置被点击了,都会触发绑定在document元素上的点击事件。想要知道事件具体是发生在哪个元素上面,可以通过事件对象提供的target属性来判断。
document.documentElement.addEventListener('click',function(e){ console.log(e.target) })
我们很容易知道事件具体是发生在哪个元素身上的。于是在上面的示例中,如果父元素document想在按钮被点击时做点什么事情,我们很自然地会这么写:
document.documentElement.addEventListener('click',function(e){ if(e.target.tagName==='BUTTON'){ console.log('按钮被点击了') } })
这时问题就出现了,按钮即使被点击了if条件也不一定成立,即也不一定会输出“按钮被点击了”。因为用户在按钮上的某个位置点击了,根据用户点击的位置,e.target可能是下面三种情况:
- BUTTON元素
- SVG元素
- USE元素
实际的情况是这样的:
我们真正的意图是,只要点击是发生在按钮上面,不论是按钮的哪个位置,我们都应视为按钮被点击了。嗯,简单,我们再改一下,这样写:
document.documentElement.addEventListener('click',function(e){ if(['BUTTON','SVG','USE'].includes(e.target.tagName.toUpperCase())){ //点击的是按钮 } })
这样似乎没什么问题,也确实可以达到目的,但看上去总是有些别扭。因为这种情况对于最上层的document来说,得知道每个子元素的情况,本来我只需要关心离我最近的button元素就可以了。
根据OOP对内封装的思想,button元素内部的事情应该在内部消化掉,其子元素对外不可见,应该只暴露button元素本身。依据这个思想和事件冒泡的特点,我们就有了比较好的解决办法:只需要禁止button内部元素的事件响应(包括事件冒泡)而只允许button元素本身的事件发生就行。有两种方式可以实现这个目的。
一种是使用CSS禁止button内部元素的事件响应:
button>*{ pointer-events:none; }
另一种是使用JS来阻止button内部元素的事件响应(包括事件冒泡):
document.querySelector('button>svg').addEventListener('click',function(e){ e.stopPropagation() e.preventDefault() }) document.querySelector('button').addEventListener('click',function(e){ console.log(e.target.tagName) })
这两种方式都能达到我们预期的效果:
综上,针对特定元素进行事件处理时,如果该元素有事件代理的情况,就要小心处理它所代理的子元素。
以上就是JavaScript事件代理需要注意的地方的详细内容,更多关于JavaScript事件代理的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。