1.事件的监听
JS有三种方法可以为事件绑定监听函数
- HTML的 on-属性:只会在冒泡阶段触发;
<!-- 正确 -->
<body onload="doSomething()">
<!-- 错误 -->
<body onload="doSomething">
- 元素节点的事件属性:只会在冒泡阶段触发;
window.onload = doSomething;
div.onclick = function (event) {
console.log('触发事件');
};
以上两种方法就是所谓的 DOM 0级事件。
- EventTarget.addEventLister();(只兼容IE8以上,attachEvent(event.type, handle )可以兼容IE8以下,只支持冒泡阶段触发)
window.addEventListener('load', doSomething, false);
target.addEventListener(type, listener[, useCapture]);
- type:事件名称;
- listener:监听函数,事件发生时,会调用该监听函数;
- useCapture:布尔值,表示监听函数是否在捕获阶段(capture)触发,默认是false,表示在冒泡阶段被触发;
- 第三个参数除了useCapture,还可以是一个属性配置对象;该属性有以下几个属性:
- capture:表示该事件是否在捕获阶段被触发;
- once:表示监听函数是否只触发一次,然后就自动移除;
- passive:表示监听函数不会调用事件的preventDefault方法,如果监听函数调用了,浏览器会忽略这个要求,然后监控台输出一行警告。
上面的方法就是所谓的 DOM 2级事件。
2.事件的传播
一个事件发生后,会在子元素和父元素之间传播。这种传播分成三个阶段:
- 第一阶段:捕获阶段,从 window 对象传导到目标节点(上层到底层);
- 第二阶段:目标阶段,在目标节点上触发。(在目标元素同时注册的冒泡和捕获事件,先注册先执行);
- 第三阶段:冒泡阶段,从目标节点传导会 window 对象。
3.阻止默认事件
- return false;阻止通过 on 方式绑定事件的默认事件;
ele.onclick = function() {
…… // 你的代码
return false; // 通过返回 false 值阻止默认事件行为
};
- event.preventDafult();阻止通过 addEventListener 添加事件的默认事件;
element.addEventListener("click", function(e){
var event = e || window.event;
……
event.preventDefault( ); // 阻止默认事件
}, false);
- event.returnValue = false;阻止通过 attachEvent() 添加事件的默认时间(主要是兼容IE8以下);
element.attachEvent("onclick", function(e){
var event = e || window.event;
……
event.returnValue = false; // 阻止默认事件
}, false);
- 阻止事件的兼容写法
// 阻止浏览器的默认行为
function stopDefault( e ) {
// 阻止默认浏览器动作(W3C)
if ( e && e.preventDefault ) {
e.preventDefault(); // IE中阻止函数器默认动作的方式
} else {
window.event.returnValue = false;
}
return false;
}
4.阻止事件冒泡
w3c 的方法是 e.stopPropagation()(阻止事件的传播),IE 则是使用 e.cancleBubble = true;
阻止事件冒泡的兼容写法
function stopBubble (e) {
// 如果提供了事件对象,则这是一个非IE浏览器
if ( e && e.stopPropagation ) {
// 因此它支持W3C的stopPropagation()方法
e.stopPropagation();
} else {
// 否则,我们需要使用IE的方式来取消事件冒泡
window.event.cancelBubble = true;
}
}
5.事件代理
由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数绑定到父节点上,有父节点的监听函数处理多个子元素的事件。这种方法就是事件的代理。
6.事件对象
- event.target:指的是触发事件的元素;
- event.currentTarget:指的是绑定事件的元素(this);
- event.preventDefault():阻止默认事件,取消事件对当前元素的影响,不会阻止事件的传播;
- event.stopPropagation():阻止事件传播,防止再触发定义在别的节点上的监听函数,但不包括当期节点上的其他的事件监听函数;
- event.stopImmediatePropagation():阻止同一事件的其他监听函数调用,不管监听函数是定义在其他节点还是当前节点
7.React 和 Vue 在事件处理上的差异
- Vue 的事件对象是原生对象,事件被挂载到当前元素上;
- 通过 event.target 获取到的是触发当前事件的元素,比如一个按钮;
- 通过 event.currentTarget 获取到的是绑定当前事件的元素,比如我是在当前按钮上绑定的事件,那获取到的就是当前的这个按钮
- React 的事件对象不是原生的对象,是 React 封装的合成对象,所有的事件都被挂载在 document 上;
- event 不是原生的事件对象,它的原型是 SyntheticEvent;
- 我们可以通过 event.target 来获取触发当前事件的元素,比如一个按钮;
- 通过 event.currentTarget 来获取绑定当前事件的元素,那么你获取到的也是这个按钮,但是这是个假象;
- 我们可以通过 event.nativeEvent 来获取到原生的事件;
- 通过 event.nativeEvent.target 来获取触发当前事件的元素,比如一个按钮;
- 通过 event.nativeEvent.currentTarget 来获取绑定当前事件的元素,这个时候你会发现你获取到的是 Document 对象;
- 那 React 为什么要使用这样一个合成对象呢?
- 更好的兼容性和跨平台;
- 挂载到 document 上,减少内存消耗,避免频繁解绑;
- 方便事件的统一管理;