注册事件(绑定事件)
1.1 注册事件
给元素添加事件,称为注册事件或者绑定事件
注册事件有两种方式:传统方式和方法监听注册方式
传统注册方式
■ 利用on开头的事件
■
■ btn.onclick = function() {}
■ 特点:注册事件的唯一性
■ 同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数会覆盖之前注册的处理函数
方法监听注册方式
■ W3C标准 (推荐)
■ addEventListener() 是一个方法
■ IE9之前不支持,可使用attachEvent() 代替
■ 特点:同一个元素同一个事件可以注册多个监听器
■ 按注册事件顺序执行
1.2 addEventListener 事件监听方式
eventTarget.addEventListener(type,listener[,useCapture])
eventTarget.addEventListener()方法将指定的监听器注册到eventTarget(目标对象)中,当对该对象触发指定的事件时,就会执行事件处理函数
该方法接受三个参数:
type:事件类型字符串,比如click、mouseover,不能带on
listener:事件处理函数,事件发生时,会调用该监听函数
useCapture:可选参数,是一个布尔值,默认是false。学完DOM事件流后,我们在进一步学习
1.3 attachEvent 事件监听方式
eventTarget.attachEvent(eventNameWithOn,callback)
eventTarget.attachEvent() 方法将指定的监听器注册到eventTarget(目标对象)中,当该对象触发指定的事件时,就会执行事件处理函数
eventNameWithOn:事件类型字符串,比如:onclick、onmouseover,这里要带on
callback:事件处理函数,当目标触发事件时回调函数被调用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button>传统注册事件</button>
<button>方法监听注册事件</button>
<button>ie9 attachEvent</button>
<script>
var btns = document.querySelectorAll('button');
btns[0].onclick = function() {
alert('1');
}
btns[0].onclick = function() {
alert('2'); //点击第一个按钮弹出 2
}
// 支持ie9以上
btns[1].addEventListener('click',function() {
alert('3'); //点击第二个按钮,第一次弹出3
})
btns[1].addEventListener('click',function() {
alert('4'); //第二次弹出4
})
//支持ie9以下
btns[2].attachEvent('onclick',function() {
alert('5'); // ie9以上不支持
})
</script>
</body>
</html>
1.4 注册事件兼容性解决方案
删除事件(解绑事件)
2.1 传统注册方式
eventTarge.onclick = null
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
width: 50px;
height: 50px;
background-color: pink;
margin: 10px;
}
</style>
</head>
<body>
<div>1</div>
<div>2</div>
<div>3</div>
<script>
var divs = document.querySelectorAll('div');
divs[0].onclick = function() {
alert(11);
// 传统方式删除事件
divs[0].onclick = null;
}
// divs[1].addEventListener('click',function(){
// alert(22);
// })
divs[1].addEventListener('click',fn);
function fn() {
alert(22);
divs[1].removeEventListener('click',fn); // 点击一次后,移除事件
}
</script>
</body>
</html>
图片点击一次后不会再响应
2.2删除事件兼容性问题解决方案
DOM事件流
事件流描述的是从页面中接收事件的顺序
事件发生时会在元素节点之间按照待定的顺序传播,这个传播过程即DOM事件流
DOM事件流分为3个阶段:
1.捕获阶段
2. 当前目标阶段
3. 冒泡阶段
■ 事件冒泡: 事件开始由最具体的元素接收,然后逐级向上传播到DOM最顶层节点的过程
■ 事件捕获: 由DOM最顶层节点开始,然后逐级向下传播到最具体的元素接收的过程
注意:
1 . JS代码中只能执行捕获或者冒泡其中一个阶段.
2. onclick和attachEvent 只能得到冒泡阶段
3. addEventListener(type,listener[,useCapture]) 第三个参数是true, 表示在事件捕获阶段. 如果第三个参数是false或不填, 表示在事件冒泡阶段.
4. 有些事件没有冒泡, 比如 onblur,onfocus, onmouseleave, onmouseenter
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
<script>
// 如果第三个参数是true,那么处于捕获阶段。顺序为:document->html->body->father->son
// 如果第三个参数是false或不填,那么处于冒泡阶段.顺序为: son->father->body->html->document
var son = document.querySelector('.son');
son.addEventListener('click',function() {
alert('son');
},true);
var father = document.querySelector('.father');
father.addEventListener('click',function() {
alert('father');
},true);
</script>
</body>
</html>
点击div第一次出现的是father,可知捕获阶段是逐级向下传播的
事件对象
4.1 事件对象简述
1.event 就是一个事件对象
2.先创建事件才能有事件对象,他是系统自动创建的,不需要我们传递参数
3.事件对象是我们事件的一系列相关数据的集合,跟事件相关的,比如鼠标点击就包含了鼠标的相关信息
如果是键盘事件,就包含与键盘有关的信息
4.事件对象可以自己命名
eventTarget.onclick = function(event) {}
eventTarget.addEventListener = function(event) {}
官方解释: event对象代表事件的状态,比如按键的状态,鼠标的位置,鼠标按钮的状态
简单解释: 事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象中,他有很多属性和方法
比如:
1.谁绑定了这个事件
2.鼠标触发事件的话,会得到鼠标的相关信息,如鼠标位置
3.键盘触发事件的话,会得到键盘的相关信息,如按了哪个键
4.2 事件对象常见的属性和方法
事件对象属性方法 | 说明 |
---|---|
e.target | 返回触发事件的对象 标准 |
e,srcElement | 返回触发事件的对象 非标准 ie678 |
e.type | 返回事件的类型 如click mouseover 不带on |
e.stopPropagation() | 该属性阻止冒泡 标准 |
e.cancelBubble | 该属性阻止冒泡 非标准 |
e.returnValue | 该属性阻止默认事件(默认行为) 比如不让链接跳转 非标准 |
e.preventDefault() | 该属性阻止默认事件(默认行为) 比如不让链接跳转 标准 |
返回触发事件
e.target 返回触发事件的对象
this 返回绑定事件的对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
width: 200px;
height: 100px;
background-color: pink;
}
li {
width: 100px;
height: 30px;
line-height: 30px;
text-align: center;
list-style: none;
background-color: pink;
border: 1px solid #999;
}
</style>
</head>
<body>
<div>123</div>
<ul>
<li>abc</li>
<li>abc</li>
<li>abc</li>
</ul>
<script>
var div = document.querySelector('div');
div.addEventListener('click',function(e) {
// e.target 返回的是触发事件的对象
console.log(e.target);
console.log(this); // this返回的是绑定事件的对象
})
var ul = document.querySelector('ul');
ul.addEventListener('click',function(e) {
console.log(this);
console.log(e.target);
})
</script>
</body>
</html>
兼容性问题
div.onclick = function() {
e = e || window.event;
var target = e.target || e.srcElement;
console.log(target);
}
阻止事件冒泡
5.1 阻止事件冒泡的两种方式
事件冒泡: 开始时由最具体的元素查收,然后逐级向上传播到DOM最顶层节点
事件冒泡本身特性, 有好有坏
e.stopPropagation() 标准
e.cancelBubble = true; 非标准 取消冒泡
事件委托(代理 委派)
点击每个li都会弹出对话框,之前需要给每个li绑定事件,DOM访问的次数越多,会延长整个页面的交互就绪时间
<ul>
<li>知否和大娘子</li>
<li>知否和大娘子</li>
<li>知否和大娘子</li>
<li>知否和大娘子</li>
<li>知否和大娘子</li>
</ul>
解决以上问题,我们可以用事件委托
事件委托也称事件代理,在jQuery中称为事件委派
事件委托的原理(重)
不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用其冒泡原理影响设置每个子节点
上面的案例,我们用事件委托: 给ul注册点击事件,然后利用事件对象的target来找到当前点击的li,因为点击li, 事件会冒泡到ul上, ul有注册事件,就会触发事件监听器.
事件委托的作用: 只需做一次DOM操作,提高了程序的性能,减少整个页面的交互就绪时间.
常用的鼠标事件
7.1 鼠标事件
鼠标事件 | 触发事件 |
---|---|
onclick | 鼠标点击左键触发 |
onmouseover | 鼠标经过触发 |
onmouseout | 鼠标离开触发 |
onfocus | 获得鼠标焦点触发 |
onblur | 失去鼠标焦点触发 |
onmousemove | 鼠标移动触发 |
onmouseup | 鼠标弹起触发 |
onmousedown | 鼠标按下触发 |
禁止鼠标右键菜单和禁止选中文字
contextmenu 主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单
selectstart 主要禁止选中文字
用e.preventDefault禁止对象的行为
<body>
<div>1111111</div>
<script>
var div = document.querySelector('div');
// 1.禁用右键菜单
div.addEventListener('contextmenu',function(e){
e.preventDefault();
})
// 2.禁止鼠标选中
div.addEventListener('selectstart',function(e) {
// 阻止这个对象的行为
e.preventDefault()
})
</script>
</body>
7.2 鼠标对象事件
event代表事件的状态,跟事件相关的一系列信息的集合.
现阶段主要使用鼠标事件对象MouseEvent 和键盘事件对象 KeyboardEvent.
鼠标事件对象 | 说明 |
---|---|
e.clientX | 返回鼠标相对于浏览器窗口可视区的X坐标 |
e.clientY | 返回鼠标相对于浏览器窗口可视区的Y坐标 |
e.pageX | 返回鼠标相对于文档页面的X坐标 IE9+ 支持 |
e.pageY | 返回鼠标相对于文档页面的Y坐标 IE9+ 支持 |
e.screenX | 返回鼠标相对于电脑屏幕的X坐标 |
e.screenY | 返回鼠标相对于电脑屏幕的Y坐标 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body {
height: 3000px;
}
</style>
</head>
<body>
<script>
document.addEventListener('click', function (e) {
// 不管页面是否往下拖动,坐标都相对于当前界面可视区
console.log('相对于当前页面可视区,X:' + e.clientX + ',Y:' + e.clientY);
// 返回相对于文档页面的坐标,页面往下拖动,页面可视区同一位置的坐标不同
console.log('相对于文档页面,X:' + e.pageX + ',Y:' + e.pageY);
// 返回页面相对于电脑屏幕的坐标
console.log('相对于电脑屏幕,X:' + e.screenX + ',Y:' + e.screenY);
})
</script>
</body>
</html>
跟随鼠标的天使案例
核心原理: 每次鼠标移动我们都会获得新的坐标,把x值和y值当作图片的left和top值就可移动图片
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
img {
position: absolute;
}
</style>
</head>
<body>
<img src="/images/angel.gif" alt="">
<script>
var pic = document.querySelector('img');
document.addEventListener('mousemove',function(e) {
// 图片要移动距离,并且不占位置,需用绝对定位
// 每次移动都要获取当前位置
var x = e.pageX;
var y = e.pageY;
pic.style.left = x - 50 + 'px';
pic.style.top = y - 40 + 'px';
})
</script>
</body>
</html>
常用的键盘事件
鼠标事件 | 触发事件 |
---|---|
onkeyup | 某个键盘按键被松开时触发 不区分大小写 |
onkeydown | 某个键盘按键被按下时触发 不区分大小写 |
onkeypress | 某个键盘按键被按下时触发 区分大小写 但他不识别功能键, 如shift , crtl, 箭头等 |
<script>
// document.onkeyup = function() {
// console.log('按键松开');
// }
// document.onkeydown = function() {
// console.log('按键按下');
// }
// document.onkeypress = function() {
// console.log('按键按下,功能键无法识别');
// }
document.addEventListener('keyup',function() {
console.log('按键松开');
})
document.addEventListener('keydown',function() {
console.log('按键按下');
})
document.addEventListener('keypress',function() {
console.log('按键按下,功能键无法识别');
})
</script>
8.1 判断用户按下哪个键
e.keyCode 返回该键的ASCII值
ASCII表
<script>
document.addEventListener('keydown', function (e) {
console.log('down:' + e.keyCode);
})
document.addEventListener('keypress', function (e) {
console.log('press:' + e.keyCode);
})
</script>
按下a, b, c 三个键
模拟京东按键输入内容
点击s键,直接跳到输入框
<body>
<input type="text">
<!-- 当我们按下s键,光标就定位到搜索框 -->
<script>
var input = document.querySelector('input');
document.addEventListener('keyup',function(e) {
// 如果是s键
if ( e.keyCode === 83) {
input.focus();
}else {
alert('不是s键');
}
})
</script>
</body>
模拟京东快递单号查询
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.search {
position: relative;
width: 178px;
margin: 100px;
}
.con {
display: none;
position: absolute;
top: -40px;
width: 171px;
border: 1px solid rgba(0, 0, 0, .2);
box-shadow: 0 2px 4px rgba(0, 0, 0, .2);
padding: 5px 0;
font-size: 18px;
line-height: 20px;
color: #333;
}
.con::before {
content: '';
width: 0;
height: 0;
position: absolute;
top: 28px;
left: 18px;
border: 8px solid #000;
border-style: solid dashed dashed;
border-color: #fff transparent transparent;
}
</style>
</head>
<body>
<div class="search">
<div class="con">123</div>
<input type="text" value="请输入您的快递单号" class="jd">
</div>
<script>
// 1.快递单号输入内容,上面的大号字体盒子(con)显示(这里面的字号更大)
// 2.表单检测用户输入:给表单添加键盘事件
// 3.把快递单号里面的值(value)获取过来赋值给con盒子(innerText)作为内容
var search = document.querySelector('.search');
var con = document.querySelector('.con');
var text = document.querySelector('.jd');
text.addEventListener('keyup', function () {
// 点击文本框,con会显示,并且内容与文本框相同
if (this.value == '') {
con.style.display = 'none';
} else {
con.style.display = 'block';
con.innerHTML = this.value;
}
})
// 当失去焦点时,con隐藏
text.addEventListener('blur', function () {
con.style.display = 'none';
})
text.addEventListener('click', function () {
if (this.value == '') {
con.style.display = 'block';
}
})
</script>
</body>
</html>