事件高级
注册事件
- 给元素添加事件,称之为注册事件或者绑定事件
- 注册事件有两种方式:传统方式和方法监听注册方式
传统注册方式
- 利用on开头的事件:如onclick
- 唯一性:同一个事件同一个元素只能设置一个处理函数,最后注册的函数将会覆盖前面注册的处理函数
<!DOCTYPE html>
<html lang="en">
<head>
<title>传统注册事件的唯一性</title>
</head>
<body>
<button>
传统注册事件测试
</button>
</body>
<script>
let btn = document.querySelector('button')
btn.onclick = function() {
// 因为会被后面一个onclick方法覆盖,所以不会执行该事件
console.log('不会被执行')
}
btn.onclick = function() {
console.log('会被执行')
}
</script>
</html>
方法监听注册方式
- addEventListener()它是一个方法(ie 9+)
- 同一个元素同一个事件可以注册多个监听器
- 按注册顺序依次执行
addEventListener 事件监听方式
- 语法规范
eventTarget.addEventListener(type, listener[, useCapture])
该方法将指定的监听器注册到eventTarget(目标对象)上,当对象出发指定的事件时,就会执行事件处理函数
type:事件类型字符串:如click,mouseover
listener:事件处理函数,事件发生时,会调用该函数
useCapture:可选参数,布尔值,默认false
<!DOCTYPE html>
<html lang="en">
<head>
<title>方法监听注册事件</title>
</head>
<body>
<button>
方法监听注册事件
</button>
</body>
<script>
let btn = document.querySelector('button')
// 第一个参数必须是字符串,并且与传统方式相比,不需要on作为前缀
btn.addEventListener('click', function() {
alert('first')
})
// last和first都会打印,有别于传统注册方式
btn.addEventListener('click', function() {
alert('last')
})
</script>
</html>
attachEvent 事件监听事件
- 非标准,不推荐使用
删除事件
删除事件的方式
传统注册方式
eventTarget.onclick = null
<!DOCTYPE html>
<html lang="en">
<head>
<title>传统注册方式删除事件</title>
</head>
<body>
<button>
传统注册方式删除事件
</button>
</body>
<script>
let btn = document.querySelector('button')
btn.onclick = function() {
alert('success')
// 设置空值,进行解绑,执行下面代码,该按钮只能实现一次弹出对话框效果,实现了注册事件解绑
btn.onclick = null
}
</script>
</html>
方法监听注册方式
-
删除使用
EventTarget.addEventListener()
方法添加的事件。使用事件类型,事件侦听器函数本身,以及可能影响匹配过程的各种可选择的选项的组合来标识要删除的事件侦听器。 -
语法
target.removeEventListener(type, listener[, options]);
target.removeEventListener(type, listener[, useCapture]);
<!DOCTYPE html>
<html lang="en">
<head>
<title>方法监听方式删除事件</title>
</head>
<body>
<button>
方法监听方式删除事件
</button>
</body>
<script>
let btn = document.querySelector('button')
// 因为在函数内部移除,所以不能使用匿名函数
// btn.addEventListener('click', function() {
// alert('success')
// })
btn.addEventListener('click', fn)
function fn() {
alert('success')
// 点击一次之后使用方法监听方式删除
btn.removeEventListener('click', fn)
}
</script>
</html>
DOM事件流
- 事件流描述的是页面中接收事件的顺序
- 事件发生时候会在特定的顺序进行传播,这个传播过程叫做DOM事件流
- 三个阶段:捕获阶段,当前目标阶段,冒泡阶段
- 对于事件代理来说,在事件捕获或者事件冒泡阶段处理并没有明显的优劣之分,但是由于事件冒泡的事件流模型被所有主流的浏览器兼容,从兼容性角度来说还是建议大家使用事件冒泡模型
- 有些事件是没有冒泡的:如onblur、onfocus、onmouseenter、onmouseleave
- 默认值为false,为冒泡,一般不需要进行设置
- 捕获和冒泡只会执行一个,都存在优先执行捕获
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
.father {
overflow: hidden;
width: 300px;
height: 300px;
margin: 100px auto;
background-color: pink;
text-align: center;
}
.son {
width: 200px;
height: 200px;
margin: 50px;
background-color: purple;
line-height: 200px;
color: #fff;
}
</style>
</head>
<body>
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
// dom 事件流 三个阶段
// 1. JS 代码中只能执行捕获或者冒泡其中的一个阶段。
// 2. onclick 和 attachEvent(ie) 只能得到冒泡阶段。
// 3. 捕获阶段 如果addEventListener 第三个参数是 true 那么则处于捕获阶段 document -> html -> body -> father -> son
// var son = document.querySelector('.son');
// son.addEventListener('click', function() {
// alert('son');
// }, true);
// var father = document.querySelector('.father');
// father.addEventListener('click', function() {
// alert('father');
// }, true);
// 4. 冒泡阶段 如果addEventListener 第三个参数是 false 或者 省略 那么则处于冒泡阶段 son -> father ->body -> html -> document
var son = document.querySelector('.son');
son.addEventListener('click', function() {
alert('son');
}, false);
var father = document.querySelector('.father');
father.addEventListener('click', function() {
alert('father');
}, false);
document.addEventListener('click', function() {
alert('document');
})
</script>
</body>
</html>
事件对象
- function里面的event就是事件对象 它写到我们侦听函数里面 可以当作形参来看待
- 事件对象只有有了事件才会存在,系统自动创建,不需要传递参数
- 事件对象是一系列相关数据的集合
- 鼠标点击事件就包含了鼠标的相关信息 如鼠标坐标等
- 如果是键盘事件里面就包含了键盘事件的信息,比如用户按下了哪个键
- 事件对象可以自己命名
<!DOCTYPE html>
<html lang="en">
<head>
<title>事件对象</title>
</head>
<body>
<div>
test
</div>
<script>
let div = document.querySelector('div')
div.onclick = function (event) {
console.log(event);
}
div.addEventListener('click', function (event) {
console.log(event)
})
</script>
</body>
</html>
事件对象的常用属性和方法
- event.target:返回触发事件的对象
<!DOCTYPE html>
<html lang="en">
<head>
<title>event.target的使用</title>
</head>
<body>
<div>
<ul>
<li>li</li>
<li>li</li>
<li>li</li>
</ul>
</div>
<script>
let ul = document.querySelector('ul')
ul.addEventListener('click', function(event){
// 我们给ul绑定了点击事件,所以this指向ul
console.log(this)
// 如果我们点击是ul里面的li元素,此时,event.target指向的是li
console.log(event.target)
})
</script>
</body>
</html>
- 返回事件类型:event.type
<!DOCTYPE html>
<html lang="en">
<head>
<title>event.type的使用</title>
</head>
<body>
<div>
test
</div>
<script>
let div = document.querySelector('div')
div.addEventListener('click', fn)
div.addEventListener('mouseover', fn)
div.addEventListener('mouseout', fn)
function fn(e) {
console.log(e.type)
}
</script>
</body>
</html>
阻止事件默认行为
- return false;也可以阻止事件默认行为,且不存在兼容性问题,但是该方法会让此语句后面的JS代码失效,所以一般不使用
<!DOCTYPE html>
<html lang="en">
<head>
<title>阻止事件默认行为</title>
<style>
</style>
</head>
<body>
<div>123</div>
<a href="http://www.baidu.com">百度</a>
<form action="http://www.baidu.com">
<input type="submit" value="提交" name="sub">
</form>
<script>
// 阻止默认行为,让链接不跳转,让按钮不提交等
var a = document.querySelector('a');
a.addEventListener('click', function (e) {
// 使用该方法后,当前事件就不会被提交,点击按钮不会产生跳转事件
e.preventDefault()
})
</script>
</body>
</html>
阻止事件冒泡
- 事件冒泡:开始由最具体的元素接收,然后逐级向上传波直到DOM最顶点
- 标准写法:利用事件对象里面的stopPropagation()方法
<!DOCTYPE html>
<html lang="en">
<head>
<title>阻止事件冒泡</title>
</head>
<body>
<ul>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
</ul>
<script>
// 事件委托的核心原理:给父节点添加侦听器, 利用事件冒泡影响每一个子节点
let ul = document.querySelector('ul');
ul.addEventListener('click', function(e){
// 利用排他思想清除上次点击效果
for (let i=0; i<ul.children.length; i++) {
ul.children[i].style = ''
}
e.target.style = 'background-color: pink;'
})
</script>
</body>
</html>
事件委托
- 事件冒泡会带来很多好处,需要我们灵活掌握
- 事件委托的原理:不需要给每个子元素节点设置监听器。而是事件监听器设置在其父节点上,利用事件冒泡传递到每个子节点
- 如果想每点击一次li就产生一个点击事件,以前需要给每个li注册事件,是非常辛苦且效率不高的,此时可以考虑事件委托
- 给ul注册点击事件,利用事件对象的target属性找到当前的li,此时点击li,事件会冒泡到ul上,ul有注册事件就会触发监听器
<ul>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
</ul>
<!DOCTYPE html>
<html lang="en">
<head>
<title>事件委托</title>
</head>
<body>
<ul>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
</ul>
<script>
// 事件委托的核心原理:给父节点添加侦听器, 利用事件冒泡影响每一个子节点
let ul = document.querySelector('ul');
ul.addEventListener('click', function (e) {
// 清除上一次点击对li样式造成的影响
for (let i = 0; i < ul.children.length; i++) {
ul.children[i].style = ''
}
// 为了防止点击ul标签也会产生效果
if (e.target.nodeName.toLowerCase() == 'li') {
e.target.style = 'background-color: pink;'
}
})
</script>
</body>
</html>
常用的鼠标事件
鼠标事件 | 触发条件 |
---|---|
onclick | 鼠标点击触发 |
onmouseover | 鼠标经过触发 |
onmouseout | 鼠标离开触发 |
onfocus | 获取鼠标焦点触发 |
onblur | 失去鼠标焦点触发 |
onmousemove | 鼠标移动触发 |
onmouseup | 鼠标弹起触发 |
onmousedown | 鼠标按下触发 |
- 禁止鼠标右键菜单
<!DOCTYPE html>
<html lang="en">
<head>
<title>阻止右键菜单</title>
</head>
<body>
我是一段不愿意分享的文字
<script>
document.addEventListener('contextmenu', function(e){
e.preventDefault()
})
</script>
</body>
</html>
- 禁止鼠标选中
<!DOCTYPE html>
<html lang="en">
<head>
<title>禁止鼠标选中</title>
</head>
<body>
我是一段不愿意分享的文字
<script>
document.addEventListener('selectstart', function(e){
e.preventDefault()
})
</script>
</body>
</html>
鼠标事件对象
- event对象代表事件的状态,跟事件相关的一系列信息的集合
- 现阶段我们主要是用的是鼠标事件对象和键盘事件对象
<!DOCTYPE html>
<html lang="en">
<head>
<title>鼠标事件对象</title>
<style>
body {
height: 3000px;
}
</style>
</head>
<body>
<script>
// 鼠标事件对象 MouseEvent
document.addEventListener('click', function(e) {
// 1. client 鼠标在可视区的x和y坐标
console.log(e.clientX);
console.log(e.clientY);
console.log('---------------------');
// 2. page 鼠标在页面文档的x和y坐标
console.log(e.pageX);
console.log(e.pageY);
console.log('---------------------');
// 3. screen 鼠标在电脑屏幕的x和y坐标
console.log(e.screenX);
console.log(e.screenY);
})
</script>
</body>
</html>
常用的键盘事件
- KeyboardEvent.keyCode:该特性已经从 Web 标准中删除,虽然一些浏览器目前仍然支持它,但也许会在未来的某个时间停止支持,请尽量不要使用该特性。
<!DOCTYPE html>
<html lang="en">
<head>
<title>常用的键盘事件</title>
</head>
<body>
<script>
document.addEventListener('keyup', function() {
console.log('我弹起了');
})
//3. keypress 按键按下的时候触发 不能识别功能键 比如 ctrl shift 左右箭头啊
document.addEventListener('keypress', function() {
console.log('我按下了press');
})
//2. keydown 按键按下的时候触发 能识别功能键 比如 ctrl shift 左右箭头啊
document.addEventListener('keydown', function() {
console.log('我按下了down');
})
// 4. 三个事件的执行顺序 keydown -- keypress -- keyup
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<title>常见的键盘事件</title>
</head>
<body>
<script>
// 键盘事件对象中的keyCode属性可以得到相应键的ASCII码值
// 1. 我们的keyup 和keydown事件不区分字母大小写 a 和 A 得到的都是65
// 2. 我们的keypress 事件 区分字母大小写 a 97 和 A 得到的是65
document.addEventListener('keyup', function(e) {
// console.log(e);
console.log('up:' + e.keyCode);
// 我们可以利用keycode返回的ASCII码值来判断用户按下了那个键
if (e.keyCode === 65) {
alert('您按下的a键');
} else {
alert('您没有按下a键')
}
})
document.addEventListener('keypress', function(e) {
// console.log(e);
console.log('press:' + e.keyCode);
})
</script>
</body>
</html>