js事件模型


简单讲述js的事件模型

EventTarget接口

  • addEventListener:绑定事件的监听函数

    这个函数用在当前节点或者对象上,定义一个特定事件的监听函数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /*调用格式:targetObject.addEventListener(type, listener[, useCapture])
    *type:事件名称,大小写敏感,例如说"click"(鼠标点击事件)
    *listener:监听函数。事件发生时会调用该监听函数。
    *useCapture:布尔值,表示函数是否在捕获阶段触发,默认为false,即监听函数只会在冒泡阶段被触发。有部分老浏览器规定该参数必选,较新版本的浏览器允许参数可选,所以为了保持兼容,建议总是写上这个参数
    */
    //实例
    var button = document.getElementById('button');
    button.addEventListener('click',()=>{
    console.log('你点击了按钮button')
    },false)

addEventListener可以为当前对象添加多个监听函数。

注意:如果为同一时间添加同一个监听函数,则该函数只会执行一次,多余的添加会被自动去除(不必使用removeEventListener手动去除)

1
2
3
4
5
6
function call_back(){
console.log('call_back')
};
button.addEventListener('click', hello, false);
button.addEventListener('click', hello, false);
//此时只会输出一次“call_back”

如果希望向监听函数传递参数,可用匿名函数包装

1
2
3
4
5
6
function print(x){
console.log(x)
}
button.addEventListener('click',() => {
print("hello")
}, false);
  • removeEventListener:移除事件的监听函数

    removeEventListener方法用来移除addEventListener方法添加的事件监听函数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    button.removeEventListener('click', listener, false)
    ```
    removeEventListener方法的参数,与addEventListener方法完全一致。它的第一个参数“事件类型”,大小写敏感。
    **注意**,removeEventListener方法移除的监听函数,必须与对应的addEventListener方法的参数**完全一致**,而且必须在**同一个**元素节点,否则无效。
    - dispatchEvent:触发事件
    dispatchEvent方法在当前节点上触发指定事件,从而触发监听函数的执行。该方法返回一个布尔值,只要有一个监听函数调用了Event.preventDefault(),则返回值为false,否则为true。
    ```javascript
    para.addEventListener('click', hello, false)
    var event = new Event('click')
    para.dispatchEvent(event)
    //可以获取到para.dispatchEvent(event)的返回值。
    //true 被点击,false 没有被点击

onClick和addEventListener的比较

  • 共同点

    都可以定义某些事件的监听代码

  • 不同点

绑定方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//onclick的绑定方法
//在html标签中
<div onclick="doSomeThing()">点击这个div就可以调用函数</div>
//在js中
//1、通过设置element节点的setAttribute方法
el.setAttribute('onclick', 'doSomeThing()')
//2、用.onclick指定监听方法
div.onclick = () => {
...
}
//addEventListener的绑定方法
//通过Element节点、document节点、window对象的addEventListener方法,也可以定义事件的监听函数。
div.addEventListener('clcik',() => {
...
},false)

在上面的三种方法中,在html中绑定监听方法在一定程度上违反了html和js代码分离的原则,而在js中通过设置onclick设置监听有一个缺点,就是同一个事件只能定义一个监听函数,重复定义的话,后一次定义会覆盖前一个,但是所有浏览器都支持着几个方法。

触发阶段

onclick的触发阶段只能在冒泡阶段出发,而addEventListener可以制定在哪个阶段(捕获阶段还是冒泡阶段)触发。
  • 推荐用法

    addEventListener:

    • 可以针对同一个事件,监听多个监听函数。
    • 能够指定在哪个阶段触发
    • 除了DOM节点外,还可以部署在window,XMLHttpRequest灯对象上面。

事件传播

事件的传播模型分成三个阶段

  • 第一阶段:从window对象传导到目标节点,称为捕获阶段(capture phase)
  • 第二阶段:在目标节点上触发。称为目标阶段(target phase)
  • 第三阶段:从目标节点传导回window对象,称为冒泡阶段(bubbling phase)

事件代理/事件委托

由于时间会在冒泡阶段向上传播到父节点,因此可以吧子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,这种方法叫做事件的代理(delegation)

这样做的好处是:只要定义一个监听函数,就能处理多个子节点的事件,而且以后再添加子节点,监听函数依然有效

1
2
3
4
5
document.getElementById("father").addEventListener('click', function(e){
if(e.target && e.target.nodeName.toUpperCase === 'LI'){
console.log(`${e.target.id}was clicked`)
}
})

如果希望事件到某个节点为止,不再传播,可以使用事件对象的stopPropagation方法。

但是stopPropagation方法只会阻止当前监听函数的传播,不会阻止同节点上的其他监听函数的传播,如果想不再触发那些监听函数,可以使用stopImmediatePropagation方法

1
2
3
4
5
6
7
p.addEventListener('click',(event) => {
event.stopImmediatePropagation()
})
p.addEventListener('click', () => {
...
//不会被触发
})

参考链接:事件模型