文章目录
DOM中的事件对象
在DOM级事件处理程序中,无论使用的是哪一级的DOM事件处理程序,都会将一个event对象传入到事件处理程序当中。
对于所有事件,一般都会有下列成员
属性/方法 | 类型 | 说明 |
---|---|---|
bubbles | Boolean | 表明事件是否可以冒泡 |
cancelable | Boolean | 是否可以取消事件的默认行为 |
currentTarget | Element | 事件处理程序当前正在到达并处理事件的那个元素 |
defaultPrevented | Boolean | 为true表示已经调用preventDefault()——DOM3级事件新增 |
detail | Integer | 与事件相关的细节部分 |
eventPhase | Integer | 调用事件处理程序的阶段 1:捕获 2:处于目标3:冒泡 |
preventDefault() | Function | 取消事件的默认行为 |
stopImmediatePropagation() | Function | 取消事件进一步冒泡,同时阻止事件处理程序被调用 |
stopPropagation() | Function | 取消事件的进一步冒泡 |
target | Element | 事件的目标 |
type | String | 事件的类型 |
在事件处理程序内部,对象this始终等于currentTarget的值。
注意区分target和currentTarget:如果事件处理程序在目标元素上,那么这两个值相等。但是如果事件处理程序在目标元素的父节点上,那么这两个值就是不相等的
let btn = document.getElementById('mybtn')
btn.onclick = function(event){
event.currentTarget === event.target //true
}
let b = document.body
b.onclick = function(event){
event.currentTarget === event.target //false
currentTarget //body
target //mybtn
}
阻止浏览器默认行为
W3C的方法是e.preventDefault(),IE则是使用e.returnValue = false
preventDefault是事件对象Event的一个方法,作用是取消一个目标元素的默认行为。如果元素没有默认行为,调用无效。什么元素有默认行为呢?如链接点我,提交按钮等
return false:
JS的return false只会阻止默认行为,而jQuery则既阻止默认行为又防止对象冒泡
阻止浏览器默认行为兼容:
function stopDefault(e) {
var e = e || window.event;
if (e && e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false;
}
return false;
}
注意:只有cancelable属性设置为true时才能过使用preventDefault取消其默认行为
阻止事件冒泡
W3C的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true
stopPropagation是事件对象Event的一个方法,作用是阻止目标元素的冒泡事件,但是不会阻止默认行为
注意,由于IE不支持事件捕获,因此e.cancelBubble = true只能停止事件冒泡,但是e.stopPropagation()可以同时取消事件捕获和事件冒泡
阻止事件冒泡兼容:
function stopPropagation(e) {
var e = e || window.event;
if ( e && e.stopPropagation ){
e.stopPropagation();
}else{
e.cancelBubble = true;
}
}
事件类型
UI事件
UI事件指的是不一定与用户操作有关的事件
- load:页面完全加载后在window上触发,当所有框架加载完毕后再框架集上触发,当图像加载完毕后在img元素上触发。
- unload:当页面完全卸载后在window上触发,当所有框架都卸载后在框架集上触发。
- resize:当窗口或框架大小变化在window或框架上面触发
- scroll:当用户滚动带滚动条的元素时在该元素上面触发
焦点事件
- blur:元素失去焦点时触发,不可以冒泡
- focus:元素获得焦点时触发,不可以冒泡
- focusin:元素获得焦点触发,可以冒泡
- focusout:元素失去焦点时触发,可以冒泡
注意:虽然blur和focus不冒泡,但是可以在事件捕获阶段侦听到他们。
当焦点从一个元素移动到另一个元素时,会依次触发下面这些事件
- focusout
- focusin
- blur
- focus
鼠标事件
鼠标事件 | 描述 |
---|---|
click | 按下鼠标时触发 |
dblclick | 双击鼠标时触发 |
mousedown | 按下鼠标键时触发 |
mouseup | 释放按下鼠标键触发 |
mousemove | 鼠标在节点内部移动触发,持续移动,事件会持续触发(会有性能问题) |
mouseenter | 鼠标首次进入节点触发,进入子节点不会触发。(在节点内只会触发一次) |
mouseover | 鼠标进入节点触发,进入子节点会再一次触发 |
mouseout | 鼠标离开节点触发,离开父节点也会触发 |
mouseleave | 鼠标离开节点触发,离开父节点不会触发 |
contextmenu | 鼠标右键(右键菜单)前触发,或按下右键菜单时触发 |
wheel | 滚动鼠标的滚轮时触发,继承WheelEvent接口 |
mouseover 和 mouseenter 的共同点:鼠标进入一个节点触发
区别:
- mouseover 会在子节点触发多次
- mouseenter 只触发一次
mouseout 和 mouseleave 共同点: 鼠标离开一个节点时触发
区别:
在父元素内部离开一个子元素时,mouseout事件会触发。
在父元素内部离开一个子元素时,mouseout事件不会触发。
鼠标事件的位置
- 客户区坐标位置
鼠标事件是在浏览器的窗口特定位置上发生的,这个位置信息保存在事件对象的clientX和clientY。 - 页面坐标位置
这个位置信心告诉你鼠标事件是在页面中什么位置发生的,保存在pageX和pageY中
PageX和clientX ,这个两个比较容易搞混,
- PageX:鼠标在页面上的位置,从页面左上角开始,即是以页面为参考点,不随滑动条移动而变化,换句话说,从滚动页面的左上角开始计算
- clientX:鼠标在页面上可视区域的位置,从浏览器可视区域左上角开始,即是以浏览器滑动条此刻的滑动到的位置为参考点,随滑动条移动 而变化.
移动端设备
由于没有鼠标,所以移动端的鼠标事件有一定区别与变化
- 不支持dbclick事件,双击浏览器窗口会放大画面,而且没有办法改变这个事件
- 点击可单机元素会触发mouseover事件,如果这个事件不会导致屏幕发生变化,那么会依次发生mousedown、mouseup、click事件。否则不再有其他事件发生
- mousemove事件也会触发mouseover和mouseout事件
触摸事件
- touchstart:手指触摸屏幕时触发
- touchmove:手指在屏幕上滑动时连续触发。在这个事件发生期间调用preventDefault()可以阻止滚动
- touchend:手指从屏幕移开时触发
- touchcancel:系统停止跟踪触摸事件时触发
html5事件
contextmenu事件
调出上下文菜单触发的事件,简单来说就是在windows下点击鼠标右键,在mac下Ctrl+单击。有时候我们需要给网页设置自定义的上下文菜单,于是contextmenu事件出现了。
由于这个事件是冒泡的,所以可以为document指定一个事件处理程序,用来代理页面中发生的所有此类事件。搭配preventDefault使用可以取消默认的上下文菜单,从而自定义上下文菜单。然后通过clientX和clientY来设置自定义菜单显示的位置,设置visible来控制自定义菜单的显示与隐藏。
beforeunload事件
在页面卸载前触发事件,让开发者在页面被卸载前阻止操作,但是需要注意的是,这个事件旨在页面卸载前提醒用户,询问用户是否离开页面,不能完全阻止页面被卸载。
DOMcontentloaded事件
- 当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表、图像和子框架的完成加载。
- load 仅用于检测一个完全加载的页面,页面的html、css、js、图片等资源都已经加载完之后才会触发 load 事件。
hashchange事件
HTML5新增的hashchange事件,以便在URL参数列表发生变化时通知开发者
前端路由的hash实现
www.test.com/#/ 就是 Hash URL,当 # 后面的哈希值发生变化时,可以通过 hashchange 事件来监听到 URL的变化,从而进行跳转页面,并且无论哈希值如何变化,服务端接收到的 URL 请求永远是 www.test.com
window.addEventListener('hashchange', () => {
// ... 具体逻辑
})
Hash 模式相对来说更简单,并且兼容性也更好
前端路由的history实现
History 模式是 HTML5 新推出的功能,主要使用 history.pushState 和 history.replaceState 改变 URL
通过 History 模式改变 URL 同样不会引起页面的刷新,只会更新浏览器的历史记录。
// 新增历史记录
history.pushState(stateObject, title, URL)
// 替换当前历史记录
history.replaceState(stateObject, title, URL)
当用户做出浏览器动作时,比如点击后退按钮时会触发 popState 事件
window.addEventListener('popstate', e => {
// e.state 就是 pushState(stateObject) 中的 stateObject
console.log(e.state)
})
两种模式对比
- Hash模式只可以更改 # 后面的内容,History 模式可以通过 API 设置任意的同源 URL
- History 模式可以通过 API 添加任意类型的数据到历史记录中,Hash 模式只能更改哈希值,也就是字符串
- Hash 模式无需后端配置,并且兼容性好。History 模式在用户手动输入地址或者刷新页面的时候会发起 URL 请求,后端需要配置 index.html 页面用于匹配不到静态资源(就像nginx配置react路由)
关于冒泡
不支持冒泡的事件
UI事件
- load
- unload
- scroll
- resize
焦点事件
- blur
- focus
鼠标事件
- mouseleave
- mouseenter