在js中可以通过onclick和addEventListener两种方式来进行事件绑定,刚好最近项目中用到了比较多的事件绑定,因此对这两种绑定方式产生了一些兴趣,这里记录一下两者的区别。
使用onclick来进行事件绑定时,可以在绑定该事件的dom元素上面查找到我们绑定的onclick事件,比如:
let el = document.getElementById("id")
el.onclick = function(e) {
console.log(e)
}
看一下打印出来的event对象,可以在target属性中看到onclick此时是有值的
而当使用addEventListener来进行事件绑定时,会发现onclick属性的值为null
let el = document.getElementById("id")
el.addEventListener('click', function(e){
console.log(e)
})
这里我去查了一下发现addEventListener把事件绑定到了一个叫做时间轮询的地方。本来想偷懒通过el.οnclick=null的方法来解绑addEventListener绑定的事件,发现行不通,只能老老实实的用removeEventListener来解除绑定…
onclick只能绑定一个事件
let el = document.getElementById("id")
el.onclick = function() {
console.log('我是第一个')
}
el.onclick = function() {
console.log('我是第二个')
}
结果:我是第二个
onclick在绑定事件时只能绑定一个事件,当绑定多次时,也只是会执行最后一次的绑定事件。
而addEventListener在进行了多次绑定后会依次执行每个绑定的事件
let el = document.getElementById("id")
el.addEventListener('click', function(){
console.log('我是第一个')
})
el.addEventListener('click', function(){
console.log('我是第二个')
})
结果:我是第一个,我是第二个
不过在这里要注意一件事情,当我们用addEventListener绑定事件时,如果绑定的是一个已经定义好的函数,即使绑定了多次,也只会执行一次,比如:
let el = document.getElementById("id")
function fn() {
console.log('我是第一个')
}
el.addEventListener('click', fn)
el.addEventListener('click', fn)
结果:我是第一个
像这样虽然绑定了两次事件,但最终只会执行一次。
addEventListener可以指定在事件流的哪个阶段触发
在dom事件流有三个阶段,分别是捕获阶段,目标执行阶段,冒泡阶段,这三个阶段就相当于是元素由外向内又由内向外执行这样一个顺序。如果使用onclick来绑定事件,只会绑定在冒泡阶段,如:
<div id='main'>
<div id='id'>点击我</div>
</div>
<script>
let dom = document.getElementById("main")
let el = document.getElementById("id")
dom.onclick = function() {
console.log('我是父元素')
}
el.onclick = function() {
console.log('我是子元素')
}
</script>
结果:我是子元素,我是父元素
经过测试可以发现,我对父子div都做了事件绑定,而当点击时,会先触发子div绑定的事件再触发父div的,也就是执行顺序是按照冒泡阶段从内向外进行的。
再使用addEventListener来绑定一遍,addEventListener的第三个参数为一个可选的布尔值,代表事件要在哪个阶段执行,true为捕获阶段,false为冒泡阶段。如:
<div id='main'>
<div id='id'>点击我</div>
</div>
<script>
let dom = document.getElementById("main")
let el = document.getElementById("id")
dom.addEventListener('click', function(){
console.log('我是父元素')
}, true)
el.addEventListener('click', function(){
console.log('我是子元素')
})
</script>
结果:我是父元素,我是子元素
由于我将父div的绑定事件设为了捕获阶段执行,所以在点击子div时,在捕获阶段就发现父div上绑定的事件要执行,所以先执行了父div的事件再执行子div的事件。
addEventListener的第三个参数默认为false,即默认绑定事件是在冒泡阶段来执行。所以上面例子如果不设第三个参数或设为false,结果就变成:我是子元素,我是父元素。
解除绑定
在文章开头有提到onclick绑定的事件可以在dom元素上找到,因此,如果想解除onclick绑定的事件,就可以直接通过element.onclick = null来将事件移除掉,如:
<div id='main'>
<div id='id'>点击我</div>
</div>
<script>
let el = document.getElementById("id")
el.onclick = function() {
console.log('我是子元素')
el.onclick = null
}
</script>
当第一次点击打印时出“我是子元素”,后面再点击无反应,因为此时onclick绑定的事件已经被移除。
removeEventListener
removeEventListener方法用来移除addEventListener绑定的事件,removeEventListener要移除的事件名必须要和addEventListener绑定的一致,否则无法移除。
<div id='main'>
<div id='id'>点击我</div>
</div>
<script>
let el = document.getElementById("id")
function fn() {
console.log('我是第一个')
}
function fun() {
console.log('我是第二个')
}
el.addEventListener('click', fn)
el.addEventListener('click', fun)
el.removeEventListener('click', fn)
</script>
结果:我是第二个
上面的例子在点击后只会打印出“我是第二个”,因为绑定的fn后面又被移除了
需要注意的是如果绑定的是匿名函数,那removeEventListener就没有办法进行移除。
<div id='main'>
<div id='id'>点击我</div>
</div>
<script>
let el = document.getElementById("id")
el.addEventListener('click', function() {
console.log('我是匿名函数')
})
el.removeEventListener('click', function() {
console.log('我是匿名函数')
})
</script>
结果:我是匿名函数
像上面代码中虽然绑定的函数与解绑的函数一样,但由于是匿名函数,是没有办法找到对应的事件进行解绑的,所以如果平时开发时有需要解绑的需求,还是使用具名函数来进行绑定比较好。