JavaScript的事件
你好! 这是我自己编辑的一些知识点。如果你想学习JavaScript的有关知识, 可以仔细阅读这篇文章,了解一下关于JavaScript的基本语法知识。
事件
事件是什么
所谓事件,就是浏览器告知JavaScript程序用户的行为。例如用户点击了HTML页面中的某个按钮,或者用户输入用户名或密码等操作。
如下实例代码,演示了如何通过事件完成用户点击按钮后的逻辑:
<div class='button-group'>
<button id='btn' class='button'>
按钮
</button>
</div>
<script>
var btn=document.getElementById('btn');
btn.onclick=function(){
consle.log('你终于点中我了');
}
</script>
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id='btn'>按钮</button>
<script>
// 获取按钮元素
var button = document.getElementById('btn');
// 事件绑定
button.onclick = function() {
console.log('你终于点中我了');
}
</script>
</body>
</html>
事件类型
事件根据使用的场景不同,可以分为如下几种:
- 依赖于设备的输入事件:键盘事件和鼠标事件,这些事件都是直接和设备相关的
- 独立于设备的输入事件:例如click事件等,这些事件并没有直接与设备相关。
- 用户界面的相关事件:用户界面事件属于较高级的事件,一般多用于表单中的插件
- 状态变化的相关事件:这些事件用户行为无关,而是由网络或浏览器触发的。
- 特定API事件:这些事件多用于特定场景的实现,例如HTML5中提供的拖放API中的事件等
- 与错误处理的相关事件
注册事件
注册事件是什么
所谓注册事件,是将JavaScript函数与指定的事件相关联,被绑定的函数成为该事件的句柄。当该事件被触发时,绑定的函数会被调用。
注册事件具有以下三种方式实现:
- HTML页面元素提供的事件属性
- DOM标准规范中HTML相关对象提供的事件属性
- 通过向HTML页面中指定元素添加事件监听器
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!--
HTML页面元素提供的事件属性 -> 元素的属性分类之一
*DOM提供了一系列的事件名称
-->
<button onclick="myClick()" id="btn">按钮</button>
<script>
function myClick() {
console.log('你终于点中我了');
}
</script>
</body>
</html>
DOM对象的事件属性
通过DOM标准规范中的Document对象定位HTML页面的元素,所返回的DOM对象提供了一系列的事件属性,通过这些事件属性可以实现注册事件的功能。
<div class='button-group'>
<button id='btn' class='button'>
按钮
</button>
</div>
<script>
var btn=document.getElementById('btn');
btn.onclick=function(){
console.log('你终于点我了');
}
</script>
通过DOM对象的事件属性方式注册事件,是不允许重复注册的。如果以这种方式为某个元素注册相同事件多次的话,只有最后一次注册的函数有效。
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id='btn' class='button'>
按钮
</button>
<script>
var btn = document.getElementById('btn');
// DOM对象的事件属性
btn.onclick = myClick;
function myClick() {
console.log('你终于点我了');
}
</script>
</body>
</html>
事件监听器
DOM标准规范提供的addEventListener()方法,调用该方法表示向指定元素添加事件监听器。
belement.addEventListener(eventName,functionName,capture)
参数名称 | 描述 |
---|---|
eventName | 为元素指定具体的事件名称(例如单击事件是click等) |
functionName | 注册事件的句柄 |
capture | 设置事件是捕获阶段还是冒泡阶段。false为默认值,表示冒泡阶段 |
<div class='button-group'>
<button id='btn' class='button'>
按钮
</button>
</div>
<script>
var btn=document.getElementById('btn');
btn.addEventListener('click',function(){
console.log('你终于点我了');
});
</script>
事件监听器中的this
当使用addEventListener()方法为某个HTML页面元素注册事件的时候,this就指代注册事件的元素。
btn.addEeventListener('click',function(){
console.log(this.textContent);
})
当使用attachEvent()方法为某个HTML页面元素注册事件的时候,this指代的是window对象,而不是注册事件的元素。
var btn=document.getElementById('btn');
btn.attachEvent('onclick',function(){
console.log(this);
})
上述代码输出的结果为[Object window].
由于addEventListener()方法中的this与attachEvent()方法中的this的含义不同,我们需要将监听器的浏览器兼容方案进行优化:
function bind(elem,event,callback){
//判断是否存在addEventListener
if(elem,addEventListener){
elem.addEventListener(event,callback,false);
}else{
elem.attachEvent('on'+event,function(){
//将this的指向修改为注册事件的元素
callback.call(elem);
})
}
}
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="btn">按钮</button>
<script>
var btn = document.getElementById('btn');
// btn.addEventListener('click', function() {
// console.log(this); // this指向当前的绑定事件的元素
// });
// btn.attachEvent('onclick', function() {
// console.log(this); //this指向当前环境的全局对象(window对象)
// });
bind(btn, 'click', function() {
// 在不同浏览器中,this指向不同
console.log(this);
});
// 提供浏览器兼容解决方案
function bind(element, eventName, functionName) {
if (element.addEventListener) {
element.addEventListener(eventName, functionName);
} else {
element.attachEvent('on' + eventName, function() {
functionName.call(element);
});
}
}
</script>
</body>
</html>
移除注册事件
DOM标准规范提供的removeEventListener()方法,调用该方法表示向指定元素移除事件监听器。
element.removeElementListener(eventName,functionName,capture)
参数名称 | 描述 |
---|---|
eventName | 表示移除的事件名称(例如单击事件是click等) |
functionName | 注册事件的句柄(之前使用addEventListener()方法定义的) |
capture | 设置事件是捕获阶段还是冒泡阶段。false为默认值,表示冒泡阶段 |
var btn=document.getElementById('btn');
function listener(){
console.log('你终于点我了');
}
btn.addEventListener('click',listener);
btn.removeEventListener('click',listener);
detachEvent()方法
移除注册事件在IE8及之前版本的浏览器都不支持removeEventListener()方法,而单独提供了detachEvent()方法。
element.detachEvent(eventName,functionName);
参数名称 | 描述 |
---|---|
eventName | 表示移除的事件名称(例如单击事件是click等) |
functionName | 注册事件的句柄(之前使用addEventListener()方法定义的) |
var btn=document.getElementById('btn');
function listener(){
console.log('你终于点到我了');
}
btn.attachEvent('click',listener);
btn.detachEvent('click',listener);
浏览器兼容
与注册事件相似,移除注册事件在实际开发中,同样需要兼容各大浏览器,具体解决方案如下:
function unbind(element, eventName, functionName) {
if (element.removeEventListener) {
element.removeEventListener(eventName, functionName);
} else {
element.detachEvent('on' + eventName, functionName);
}
}
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="btn">按钮</button>
<script>
var btn = document.getElementById('btn');
function myClick() {
console.log('xxxx');
};
btn.addEventListener('click', myClick);
btn.addEventListener('click', function() {
console.log('yyyy.');
});
// 移除注册事件 - removeEventListener(eventName,functionName)方法
// *参数
// *eventName - 表示移除的事件名称
// *functionName - 表示事件的处理函数
// *必须是注册事件时的处理函数(同一个函数)
btn.removeEventListener('click', myClick);
// IE8以下版本浏览器不支持removeEventListener()方法
// *detachEvent(eventName,functionName)
// *eventName - 表示移除的事件名称(必须有on)
// *functionName - 表示事件的处理函数
// * 必须是注册事件时的处理函数(同一个函数)
function unbind(element, eventName, functionName) {
if (element.removeEventListener) {
element.removeEventListener(eventName, functionName);
} else {
element.detachEvent('on' + eventName, functionName);
}
}
</script>
</body>
</html>
Event事件对象
事件对象是什么
为HTML页面中的元素注册事件时,事件的处理函数具体一个参数,该参数就是Event事件对象。
Event事件对象中包含了该事件的信息,以及该事件发生在哪个元素上。
element.addEventListener(eventName,function(event){
//event就是事件对象
},capture);
注意:
- 当事件发生时,Event事件对象会被创建并依次传递给事件监听器。
- 由于Event事件对象是事件处理函数的参数,所以参数名允许自定义的。
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="btn">按钮</button>
</body>
<script>
var btn = document.getElementById('btn');
// 事件的处理函数中接收一个参数 - 事件对象
btn.addEventListener('click', function(event) {
// Event事件对象 - 作为所有事件对象的父级
// MouseEvent 事件对象 - 表示鼠标事件
// keyboardEvent事件对象 - 表示键盘事件
// TouchEvent事件对象 - 表示触摸事件
console.log(event);
});
</script>
</html>
浏览器兼容
IE8及之前版本浏览器,HTML页面元素注册事件时,Event事件对象并不是作为事件的处理函数的参数,而是作为window对象的属性存在的。
<div class='button-group'>
<button id='btn' class='button'>
按钮
</button>
</div>
<script>
var btn=document.getElementById('btn');
btn.attachEvent('onclick',function(){
console.log(window.event);
});
</script>
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- this指向当前元素 -->
<!-- <button id="btn" onclick="myClick(this)">按钮</button> -->
<button id="btn" onclick="myClick(event)">按钮</button>
</body>
<script>
var btn = document.getElementById('btn');
// // 事件的处理函数中接收一个参数 - 事件对象
// btn.addEventListener('click', function(event) {
// // Event事件对象 - 作为所有事件对象的父级
// // MouseEvent 事件对象 - 表示鼠标事件
// // keyboardEvent事件对象 - 表示键盘事件
// // TouchEvent事件对象 - 表示触摸事件
// console.log(event);
// });
// // IE8以下版本浏览器提供的添加事件监听器方法 - 事件对象是作为window对象的属性出现
// btn.attachEvent('onclick', function(event) {
// console.log(window.event);
// });
// function bind(element, eventName, functionName) {
// if (element.addEventListener) {
// element.addEventListener(eventName, functionName);
// } else {
// element.attachEvent('on' + eventName, function() {
// functionName.call(element);
// });
// }
// }
// bind(btn, 'click', function(event) {
// var e = event || window.event;
// });
// btn.onclick = function(event) {
// console.log(event);
// }
function myClick(event) {
console.log(event);
}
</script>
</html>
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// document对象和<html>绑定鼠标点击事件有效的
var html = document.documentElement;
var body = document.body;
// click事件 - 表示鼠标点击事件(鼠标左键)
// mousedown事件 - 表示鼠标按键按下事件
// mouseup事件 - 表示鼠标按键被释放事件
html.addEventListener('mousedown', function(event) {
// event事件对象提供了button属性
// 作用 - 用于表示鼠标按键
// 值
// * 0 - 表示鼠标左键
// * 1 - 表示鼠标滚轮
// * 2 - 表示鼠标右键
if (event.button === 2) {
console.log('xxx.');
// 提供一个自定义的菜单
}
});
</script>
</body>
</html>
获取目标元素
target属性
Event事件对象提供了target属性,用于获取触发当前事件的HTML元素。
<ul id='li' class='list-group'>
<li class='list-group-item'><a href='#'>链接</a></li>
</ul>
<script type='text/javascript'>
var li=document.getElementById('li');
li.addEventListener('click',function(event){
console.log(event.target);
});
</script>
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
ul {
background-color: beige;
}
#mi {
background-color: cadetblue;
}
a {
background-color: chocolate;
}
</style>
</head>
<body>
<ul id="phone">
<li>苹果</li>
<li id="mi"><a href="#">小米</a></li>
<li>华为</li>
</ul>
<script>
var phone = document.getElementById('phone');
phone.addEventListener('click', function(event) {
// target属性 - 获取触发当前事件的目标元素
console.log(event.target);
});
</script>
</body>
</html>
currentTarget属性与this
事件处理函数中的this,作用于事件对象的currentTarget属性相同,可以获取注册当前事件的HTML元素。
<ul id='li' class='list-group'>
<li class='list-group-item'><a href='#'>链接</a></li>
</ul>
<script type='text/javascript'>
var li=document.getElementById('li');
li.addEventListener('click',function(event){
console.log(this);
});
</script>
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
ul {
background-color: beige;
}
#mi {
background-color: cadetblue;
}
a {
background-color: chocolate;
}
</style>
</head>
<body>
<ul id="phone">
<li>苹果</li>
<li id="mi"><a href="#">小米</a></li>
<li>华为</li>
</ul>
<script>
var phone = document.getElementById('phone');
phone.addEventListener('click', function(event) {
// target属性 - 获取触发当前事件的目标元素
console.log(event.target);
// currentTarget属性 - 获取绑定当前事件的目标元素
console.log(event.currentTarget);
// this等同于currentTarget属性 - 获取绑定当前事件的目标元素
console.log(this);
});
// IE8以下版本浏览器提供srcElement属性 - (target)目标元素
phone.attachEvent('onclick', function(event) {
var e = event || window.event;
console.log(e.srcElement);
});
</script>
</body>
</html>
阻止默认行为
所谓默认行为,就是指HTML元素不借助JavaScript逻辑原本具有的动态效果。例如以下HTML元素:
- a元素的跳转功能。
- form元素中点击input type='submit’提交按钮时,提交表单功能。
- 输入框的输入文本内容功能。
- 单选框或复选框的切换选项功能。
preventDefault()方法
Event事件对象提供了preventDefault()方法,用于阻止HTML元素的默认行为。
<a class='button' id='a' href='#'>
链接
</a>
<script>
var a=document.getElementById('a');
a.onclick=function(event){
event.preventDefault();
}
</script>
浏览器兼容
IE8及之前版本的浏览器,并不支持preventDefault()方法,而是提供了returnValue属性实现相同功能。
<a class='button' id='a' href='#'>链接</a>
<script>
var a=document.getElementById('a');
a.onclick=function(event){
if(event.preventDefault){
event.preventDefault();
}else{
event.returnValue=false;
}
}
</script>
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<a href="#">链接</a>
<script>
var aElement = document.getElementsByTagName('a')[0];
// aElement.addEventListener('click', function(event) {
// event.preventDefault(); //阻止默认行为
// })
aElement.onclick = function(event) {
// event.preventDefault();//阻止默认行为
// return false; - return语句
// *作用 - 当前函数是事件的处理函数时,阻止默认行为
// *注意 - return语句之后的逻辑代码不会被执行
// *编写在函数体的最后面
// *只有在DOM对象的事件属性中具有阻止默认行为的功能
return false;
}
aElement.attachEvent('onclick', function(event) {
var e = event || window.event;
e.returnValue = false; //阻止默认行为
})
</script>
</body>
</html>
获取鼠标坐标
鼠标坐标相关属性
Event事件对象提供了触发注册事件时,有关鼠标的坐标值相关属性:
- pageX和pageY:表示鼠标在整个页面中的位置。如果页面过大(存在滚动条),部分页面可能存在可视区域之外。
- clientX和clientY:表示鼠标在整个可视区域中的位置。
- screenX和screenY:表示鼠标在整个屏幕中的位置。从屏幕(不是浏览器)的左上角开始计算。
- offsetX和offsetY:表示鼠标相对于定位父元素的位置。
鼠标相对页面的坐标
pageX和pageY属性表示鼠标相对于页面的坐标值。
注意:部分页面可能会在浏览器可视窗口的外面。如果部分页面存在可视窗口外面的话,相对于页面的坐标值会大于相对于可视窗口的坐标值。
鼠标相对可视窗口的坐标
clientX和clientY鼠标表示相对于可视窗口的坐标值。
注意:clientX和clientY表示鼠标相对于浏览器可视窗口的坐标,是不包含浏览器的地址栏、工具栏等区域的。
鼠标相对于屏幕的坐标
screenX与screenY属性表示相对于电脑屏幕的坐标值。
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body {
height: 2000px;
}
</style>
</head>
<body>
<script>
var html = document.documentElement;
html.addEventListener('click', function(event) {
// 鼠标坐标值相对于当前HTML页面
console.log(event.pageX, event.pageY);
// 鼠标坐标值相对于当前可视区域
console.log(event.clientX, event.clientY);
// 鼠标坐标值相对于当前屏幕
console.log(event.screenX, event.screenY);
// 鼠标坐标值只能获取,不能设置
})
</script>
</body>
</html>
获取相对于定位父元素的鼠标坐标值
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#d1 {
width: 400px;
height: 400px;
border: 1px solid black;
margin: 300px 0 0 300px;
}
</style>
</head>
<body>
<div id="d1"></div>
<script>
// 相对于指定元素的鼠标坐标值
var div = document.getElementById('d1');
div.addEventListener('click', function(event) {
console.log(event.offsetX, event.offsetY);
})
</script>
</body>
</html>
事件流
事件流是什么
所谓事件流,就是当触发某个元素的事件时,事件会按照DOM树结构进行传播,传播的过程分为捕获阶段、目标阶段和冒泡阶段三个阶段。
1.捕获阶段:该阶段是由网景公司提出的按照DOM树结构由document对象向下的顺序传播,直到目标元素为止。
2.目标阶段:该阶段就是指目标元素触发当前事件。
3.冒泡阶段:该阶段是由微软公司提出的,按照DOM树结构由目标元素向上的顺序传播,直到document对象为止。
事件监听器
事件监听器addEventListener()方法的第三个参数的作用,就是设置当前注册的事件是捕获阶段还是冒泡阶段。
element.addEventListener(eventName,functionName,capture);
上述语法结构中,参数的具体说明如下:
参数名称 | 描述 |
---|---|
eventName | 为元素指定具体的事件名称(例如单击事件是click等) |
functionName | 注册事件的句柄 |
capture | 设置事件是捕获阶段还是冒泡阶段。false为默认值,表示冒泡阶段 |
取消事件冒泡
当元素注册事件设置为冒泡阶段时,可以通过事件对象的**stopPropagation()**方法取消事件冒泡。
var d1=document.getElementById('d1');
d1.addEventListener('click',function(){
alert(this.id);
},false);
var d2=document.getElementById('d2');
d2.addEventListener('click',function(){
alert(this.id);
},false);
var d3=document.getElementById('d3');
d3.addEventListener('click',function(event){
alert(this.id);
event=event || window.evnt;
event.stopPropagation();
},false);
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#d1 {
width: 200px;
height: 200px;
padding: 50px;
background-color: rgb(216, 216, 216);
}
#d2 {
width: 100px;
height: 100px;
padding: 50px;
background-color: rgb(233, 230, 192);
}
#d3 {
width: 100px;
height: 100px;
background-color: rgb(159, 228, 228);
}
</style>
</head>
<body>
<div id="d1">
<div id="d2">
<div id="d3"></div>
</div>
</div>
<script>
var d1 = document.getElementById('d1');
d1.addEventListener('click', function() {
console.log('这是d1....');
}, false);
var d2 = document.getElementById('d2');
d2.addEventListener('click', function(event) {
console.log('这是d2....');
event.stopPropagation();
}, false);
var d3 = document.getElementById('d3');
d3.addEventListener('click', function(event) {
console.log('这是d3....');
event.stopPropagation();
}, false);
</script>
</body>
</html>
事件委托
事件委托是什么
当为大量的HTML元素注册相同事件,并且事件的句柄逻辑完全相同时,会造成页面速度下降。不过,事件流允许在这些HTML元素的共同父级元素注册事件。这种方式被称为事件委托。
<div id='parent' class='button-group'>
<button>按钮</button>
<button>按钮</button>
<button>按钮</button>
</div>
<script>
var btn=document.getElementById('parent');
btn.addEventListener('click',function(event){
if(event.target.nodeName==='BUTTON'){
alert('我是一个链接。')
}
})
</script>
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="con">
<button id="btn1">按钮</button>
<button id="btn2">按钮</button>
<button id="btn3">按钮</button>
</div>
<script>
// var btn1 = document.getElementById('btn1');
// btn1.addEventListener('click', function() {
// console.log('这是一个按钮');
// });
// var btn2 = document.getElementById('btn2');
// btn2.addEventListener('click', function() {
// console.log('这是一个按钮');
// });
// var btn3 = document.getElementById('btn3');
// btn3.addEventListener('click', function() {
// console.log('这是一个按钮');
// });
// 不将事件绑定给指定元素,而是绑定给共同的父级/祖先元素
var con = document.getElementById('con');
con.addEventListener('click', function(event) {
var target = event.target; //触发事件的目标元素
if (target.nodeName === 'BUTTON') {
console.log('这是一个按钮');
}
})
</script>
</body>
</html>