事件是我们开发过程中经常会用到的,像click,load,mouseenter,mouseleave等等。而我们在使用这些事件的时候,经常会忽略了它们的历史渊源。
DOM(Document Object Model,即文档对象模型)级别经历了从DOM0到DOM3的变迁。而关于事件的级别却只有DOM0级,DOM2级,DOM3级三种,独独缺了DOM1级事件,因为在DOM1阶段,W3C并未对事件这方面做什么改动。
DOM0级事件约束了事件的绑定方式,有两种方式。
document.getElementById('btn').onclick = function(e) {
console.log(e)
}
只要给该事件赋值null即可
document.getElementById('btn').onclick = null
没有兼容问题,各大浏览器均支持。
每个元素的每种事件只能绑定一个事件处理器
DOM2级提供了更灵活的事件监听方式。
可以为元素添加多个事件处理函数,而事件触发时会按照添加时的顺序依次调用。写法如下:
document.getElementById('btn').addEventListener('click', function(e) {
console.log(e)
}, true)
addEventListener 接收三个参数,第三个参数决定了事件处理函数的执行时机,true表示在事件捕获阶段执行,而false表示在事件冒泡阶段执行。默认为false
注意:IE对addEventListener的支持性不是很好,从Can I Use上可以看到,IE11才完全支持addEventListener
IE支持的是attachEvent,因此为了兼容IE低版本,我们需要自己封装一下代码
function addEvent(element, type, callback, isCapture) {
if (event.addEventListener) {
// 如果支持DOM2级addEventListener
element.addEventListener(type, callback, isCapture)
} else if (element.attachEvent) {
// 如果支持IE attachEvent
element.attachEvent('on' + type, callback)
} else {
// 啥都不支持,别说了,用最老套的吧
element['on' + type] = callback
}
}
这里又必须啰嗦一下事件捕获与事件冒泡的区别了。
事件捕获是指事件从最不确定的对象(body)开始触发,然后到最精确的事件绑定的对象上。
事件冒泡则与之相反,从事件绑定的对象开始触发,一直传播到body
通俗地讲,事件捕获从爷爷辈开始触发,继而通知到父亲,最后通知到本人;而事件冒泡从本人开始触发,然后会把事件通知到父亲,爷爷,祖爷爷等等。
事件冒泡往往是我们不想要的结果。你把事件告诉我就行了,还TM告诉其他人干嘛,这不是浪费人力资源吗?那么如何阻止事件冒泡呢?
W3C标准中指定的阻止冒泡的方法为e.stopPropagation(),但是IE你懂的,低版本IE不支持。兼容写法如下:
function stopPropagation(event) {
if (event.stopPropagation) {
event.stopPropagation()
} else {
event.cancelBubble = true
}
}
与addEventListener类似,用法如下:
document.getElementById('btn').removeEventListener('click', function(e) {
console.log(e)
}, true)
兼容IE
function removeEvent(element, type, callback, isCapture) {
if (event.removeEventListener) {
// 如果支持DOM2级removeEventListener
element.removeEventListener(type, callback, isCapture)
} else if (element.detachEvent) {
// 如果支持IE detachEvent
element.detachEvent('on' + type, callback)
} else {
// 啥都不支持,别说了,用最老套的吧
element['on' + type] = null
}
}
浏览器有一些事件的默认行为,如点击a标签会打开新链接,点击右键会弹出菜单。有些场景下,我们需要阻止事件的默认行为。标准的方法是preventDefault(),但是为了兼容IE,我们经常需要这样写:
function stopDefault(event) {
if (event.preventDefault) {
event.preventDefault()
} else {
// 或者return false,该语法实质在操作window.event.returnValue的值
window.event.returnValue = false;
}
}
要知道,return false其实是阻止了事件的继续执行,所以说,在阻止默认事件行为的同时,它也阻止了冒泡,这一点上与preventDefault 方法还是有区别的。但是在网上看到一哥们提到,return false 不是每次都有用,特别是在mouseover等一些特殊事件上。所以不要过分地依赖return false
DOM3级事件在DOM2级事件的基础上新增了更多的事件类型,主要有:
UI事件,如:load、scroll
焦点事件,元素获得或失去焦点时触发,如:blur、focus
鼠标事件,用户通过鼠标在页面执行操作时触发如:dbclick、mouseup
滚轮事件,使用鼠标滚轮或类似设备时触发,如:mousewheel
键盘事件,如:keydown、keyup、keypress
变动事件,DOM结构发生变化时触发,如:DOMsubtreeModified
DOM3还支持用户自定义事件,主要API有三个
// 创建自定义事件
document.createEvent(customedEventName)
// 事件初始化
event.initEvent()
// 事件触发
element.dispatchEvent()
本人也没用过自定义事件,目前不知道实际应用场景。