一、注册和解绑事件
1.1.传统注册和解绑事件方式
1.1.1.传统注册
事件源 . 事件类型 = function(){}
- 特点:注册事件的
唯一性
同一个元素的同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖最前面注册的处理函数
<button>1</button>
<button>2</button>
<script>
var btns=document.querySelectorAll('button')
btns[0].onclick = function(){
alert("hbsd1")
}
// 第一个被覆盖,只会执行第二个
btns[0].onclick = function(){
alert("hbsd2")
}
</script>
1.1.2.传统解绑
事件源 . 事件类型 = null
btns[0].onclick = function(){
alert("hbsd1")
btns[0].onclick = null // 传统方式解绑事件
}
1.2.方法监听注册和解绑方式
1.2.1.监听注册
事件源 . addEventListener('事件类型',function(){},false)
addEventListener()
:w3c标准推荐,IE9之前不支持,可以使用attachEvent()
代替- 特点:同一个元素同一个事件可以注册多个监听器(function),按照顺序依次执行
addEventListener方法的参数 | 解释 |
---|---|
type | 事件类型,如click,mouseover(不用加on,而且是字符串类型,需要加引号) |
listener | 事件处理函数(function)(监听器) |
useCapture | 可选参数,默认false |
<button>传统注册</button>
<button>监听注册</button>
<script>
var btns=document.querySelectorAll('button')
// 同一个元素 同一个事件可以添加多个监听器(事件处理程序)
btns[1].addEventListener('click',function(){
alert("监听注册1")
})
btns[1].addEventListener('click',function(){
alert("监听注册2")
})
</script>
1.2.2.监听解绑
事件源.removeEventListener('事件类型',函数名)
注意:事件处理函数不能使用匿名函数
// 如果后续需要解绑事件,事件处理函数不能使用匿名函数(必须写到外面),并且调用的时候不需要加括号
btns[1].addEventListener('click',fn1)
function fn1(){
alert("监听注册1")
// removeEventListener解绑事件
btns[1].removeEventListener('click',fn1)
}
1.3.IE9以前的方法监听注册和解绑方式
1.3.1.监听注册
事件源.attachEvent(事件类型,回调函数)
:非标准,了解即可
addEventListener方法的参数 | 解释 |
---|---|
eventNameWithOn | 事件类型,如onclick,onmouseover(需要加on,而且是字符串类型,需要加引号) |
callback | 事件处理函数(function)(回调函数) |
btns[2].attachEvent('onclick',function(){
alert("ie9前 监听注册")
})
1.3.2.监听解绑
事件源.detachEvent('on+事件类型',函数名)
btns[2].attachEvent('onclick',fn2)
function fn2(){
alert("ie9前 监听注册")
// removeEventListener解绑事件
btns[2].detachEvent('onclick',fn2)
}
1.4.兼容性封装注册和解绑函数
1.4.1.注册函数
兼容性处理原则:先照顾大多数浏览器,再处理特殊浏览器
<button>函数注册</button>
<script>
var btns=document.querySelectorAll('button')
function addEventListener(element,eventName,fn){
// 判断当前浏览器是否支持addEventListener方法
if(element.addEventListener){
element.addEventListener(eventName,fn) // 第三个参数默认false
}else if(element.attachEvent){
element.attachEvent('on'+eventName,fn) // ie9
}else{
element['on'+eventName]=fn // 传统方式,相当于element.οnclick=fn
}
}
addEventListener(btns[3],'click',function(){alert("函数")})
</script>
1.4.2.解绑函数
function removeEventListener(element,eventName,fn){
if(element.removeEventListener){
element.removeEventListener(eventName,fn) // 第三个参数是false
}else if(element.detacEvent){
element.detacEvent('on'+eventName,fn)
}else{
element['on'+eventName] = null
}
}
二、DOM事件流
2.1.DOM事件流的3个阶段
事件流:描述从页面中接收事件的顺序
事件发生时会在元素节点中间按照特定的顺序传播,这个传播过程即DOM事件流
- DOM事件流的3个阶段
1.捕获阶段:由最顶层DOM节点(Document)逐级向下传播到具体元素的过程(网景最早弹出)
2.当前目标阶段:绑定事件的元素
3.冒泡阶段:从事件源开始,逐级向上传播到DOM最顶层节点的过程(IE最早提出)
2.2.DOM事件流3个阶段的验证
- JS代码只能同时执行捕获或冒泡的一个阶段
addEventListener(事件类型,事件处理函数,第三个参数)
第三个参数为true时,表示事件捕捉阶段调用事件处理程序
捕获阶段 document - html - body - father - son(从上至下)
第三个参数为false时,表示事件冒泡阶段调用事件处理程序
冒泡阶段 son - father - body - html - document(从下至上)- onclick和attachEvent,只能得到冒泡阶段
- onbulr、onfouse、onmouseover和onmouseleave,这些事件是没有冒泡的
- 实际开发中很少关注事件捕获,更关注事件冒泡
<div class="father">
<div class="son">son_div</div>
</div>
<script>
var father = document.querySelector('.father')
var son=document.querySelector('.son')
// addEventListener的第三个参数为 true 为捕获阶段
// 捕获阶段 document - html - body - father - son
// 点击son的div 先弹出 father ,再弹出 son
son.addEventListener('click',function(){alert('son')},true)
father.addEventListener('click',function(){alert('father')},true)
// addEventListener的第三个参数为 false 为冒泡阶段
// 冒泡阶段 son - father - body - html - document
// 点击son的div 先弹出 son ,再弹出 father
son.addEventListener('click',function(){alert('son')},false)
father.addEventListener('click',function(){alert('father')},false)
</script>
三、事件对象
事件源 . 事件类型 = function(event) {}
- event是事件对象,存储一系列跟时间相关的信息数据集合,包含很多属性和方法
若鼠标触发事件,会得到鼠标相关信息,如点击时鼠标的位置,鼠标按钮状态
若键盘触发事件,会得到键盘相关信息,如按了键盘那个键- event是一个形参,由系统自动创建并设定为事件对象,无须传递实参,依次被传递给事件监听器
- event可以自己设置,可以是 evt 或 e
- 有兼容性问题,ie 6,7,8不识别,需要使用window.event来获取
兼容性处理 e = e || window.event
3.1.事件对象的常见属性和方法
属性或方法 | 说明 |
---|---|
e.target | 返回触发事件对象(事件源,标准) |
e.srcElement | 返回触发事件对象(非标准,ie6-8使用) |
e.type | 返回事件类型(如click,mouseover,不带on) |
e.preventDefault() | 阻止默认事件(如不让链接跳转)(标准) |
e.returnValue | 阻止默认事件(如不让链接跳转)(非标准,ie6-8使用) |
e.stopProgapation() | 阻止冒泡(标准) |
e.cancelBubble | 阻止冒泡(非标准,ie6-8使用) |
3.1.2.this 与 target 的区别
this:指向绑定事件的对象(元素)
e.target:指向触发事件的对象(元素)
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script>
// 给ul绑定事件,但点击的有可能是里面的小li
// this返回的是ul,e.target返回的是被点击的小li
var ul=document.querySelector('ul')
ul.addEventListener('click',function(e){
// 点击第2个小li
console.log(this) // 返回ul
console.log(e.currentTarget) // 返回ul(与this相似,但有兼容性问题,ie6-8不兼容)
console.log(e.target) // 返回第2个li
})
// ie6-8 兼容性处理 e 和 target
ul.onclick = function(e){
e = e || window.event
var target = e.target || e.srcElement
console.log(target)
}
</script>
3.1.3.阻止默认事件
- e.preventDefault() :方法
- e.returnValue:属性
- return false
<a href="http://www.baidu.com">百度</a>
<script>
var a = document.querySelector('a')
// 传统注册方式 阻止跳转 的3种方式
a.onclick = function(e){
e.preventDefault() // 普通浏览器
e.returnValue // ie6-8浏览器
return false // 没有兼容性问题,但return后面的代码无法继续执行
}
// addEventListener注册方式 阻止跳转
a.addEventListener('click',function(e){
e.preventDefault() // dom标准
})
</script>
3.1.3.阻止事件冒泡
- e.stopPropagation
- event.cancelBubble = true
<script>
// addEventListener的第三个参数为 false 为冒泡阶段
// 冒泡阶段 son - father - body - html - document
// 点击son的div 先弹出 son ,再弹出 father
son.addEventListener('click',function(e){
alert('son')
if(e && e.stopPropagation){
e.stopPropagation() // 停止冒泡,有兼容性问题
}else{
window.event.cancelBubble = true // 停止冒泡,解决兼容性问题
}
},false)
father.addEventListener('click',function(){alert('father')},false)
document.addEventListener('click',function(){alert('document')},false)
</script>
3.1.4事件委托(代理)
- 原理(面试常问):
将事件委托给当前操作元素的父节点(将事件监听器设置在其父节点上),再利用
冒泡原理影响设置每个子节点
(而不是给每个子节点单独设置事件监听器)
案例:给ul注册点击事件,利用target找到当前点击的li,点击li会冒泡到ul上,ul上注册了事件,就会触发监听器
<!-- 事件委托 -->
<!-- 不给li设置点击事件,而给ul设置点击事件,通过点击li,然后冒泡到ul,触发ul绑定的事件 -->
<!-- 期间可以通过e.target获得被点击的li,并对li进行相关的样式和属性的操作 -->
<ul>
<li>知否知否1</li>
<li>知否知否2</li>
<li>知否知否3</li>
<li>知否知否4</li>
</ul>
<script>
var ul=document.querySelector('ul')
ul.addEventListener('click',function(e){
// 将被点击的li背景颜色改成红色
e.target.style.backgroundColor = 'red'
})
</script>
3.1.5.禁止复制或选中文字
- contextmenu:禁止右键复制文字
- selectstart:禁止复制文字
<P>我是一段不愿意被分享的文字</P>
<script>
var p=document.querySelector('p')
// contextmenu 禁用触发右键菜单(禁止复制,但任然可以ctrl+c粘贴)
p.addEventListener('contextmenu',function(e){
e.preventDefault() // 阻止选中文字后默认弹出的右键菜单
})
// selectstart 禁止文字被选中(可以禁止复制和粘贴)
p.addEventListener('selectstart',function(e){
e.preventDefault()
})
</script>
3.2.鼠标事件对象MouseEvent
鼠标事件 | 解释 |
---|---|
onmouseover | 鼠标经过触发 |
onmouseout | 鼠标离开触发 |
onmousemove | 鼠标移动触发 |
onmouseup | 鼠标弹起触发 |
onmousedown | 鼠标按下触发 |
MouseEvent事件在页面中的坐标 | 解释 |
---|---|
e.clientX | 在可视区域内,获取鼠标点击处距离 浏览器 左边框的距离,滚动条滚动时距离不变 |
e.clientY | 在可视区域内,获取鼠标点击处距离 浏览器 上边框的距离,滚动条滚动时距离不变 |
e.pageX | 在可视区域内,获取鼠标点击处距离 文档 左边框的距离,滚动条滚动时距离不变,兼容性(IE9以上才支持) |
e.pageY | 在可视区域内,获取鼠标点击处距离 文档 上边框的距离,滚动条滚动时距离不变,兼容性(IE9以上才支持) |
e.screenX | 在可视区域内,获取鼠标点击处距离 电脑屏幕 左边框的距离,滚动条滚动时距离不变 |
e.screenY | 在可视区域内,获取鼠标点击处距离 电脑屏幕 上边框的距离,滚动条滚动时距离不变 |
<script>
document.addEventListener('mousedown',function(e){
console.log(e) // 注意:click获取的是PointEvent,mousedown获取的是MouseEvent
console.log(e.clientX) // 在可视区域内,获取鼠标点击处距离 浏览器 左边框的距离,滚动条滚动时距离不变
console.log(e.clientY) // 在可视区域内,获取鼠标点击处距离 浏览器 上边框的距离
console.log(e.pageX) // 在可视区域内,获取鼠标点击处距离 文档 左边框的距离,跟着滚动条滚动的距离变化,兼容性(IE9以上才支持)
console.log(e.pageY) // 在可视区域内,获取鼠标点击处距离 文档 上边框的距离
console.log(e.screenX) // 在可视区域内,获取鼠标点击处距离 电脑屏幕 左边框的距离,当前浏览器窗口放大缩小会有影响
console.log(e.screenY) // 在可视区域内,获取鼠标点击处距离 电脑屏幕 上边框的距离
})
</script>
3.3.键盘事件对象KeyBoardEvent
键盘事件 | 说明 |
---|---|
keydown | 键盘按下 |
keyup | 键盘弹起 |
keypress | 键盘按下(注意:不识别功能键,如ctrl shift 箭头等) |
KeyBoardEvent键盘事件对象 | 解释 |
---|---|
keyCode | 获得的按下键的ASCII码值(keydown 和 keyup不区分大小写,keypress区分大小写) |
// 三个事件的执行顺序,先keydown - keypress - keyup
// keydown 和 keyup 使用 keyCode 获得的按下键的ASCII码值 不区分大小写(都按小写走)
// keypress 使用 keyCode 获得的按下键的ASCII码值 区分大小写
document.addEventListener('keydown',function(e){
console.log('down:'+e.keyCode)
})
document.addEventListener('keypress',function(e){
console.log('press:'+e.keyCode)
})
document.addEventListener('keyup',function(e){
console.log('up:'+e.keyCode)
})