事件监听器
事件处理器
在前面的学习中,如果我们要给元素添加一个事件,一般会通过操作 HTML 属性的方式来实现,这种方式其实也叫作“事件处理器”,如下所示。
oBtn.onclick = function(){...};
虽然这种方式简单高效,但是当一个元素有如下情况时:
oBtn.onclick = function(){OPTION1};
oBtn.onclick = function(){OPTION2};
oBtn.onclick = function(){OPTION2};
JavaScript 最终只会执行最后一次 onclick。可以看出,事件处理器不能为一个元素添加多个相同事件。
对于同一个元素来说,确实很少需要添加多个相同事件。可是,有些情况下也确实需要这么做,如在点击【提交表单】按钮时,需要验证用户输入的全部数据,然后再通过 AJAX 将其提交给服务器。
如果要为一个元素添加多个相同的事件,该如何实现呢?这就需要用到另外一种添加事件的方式了,那就是——事件监听器。
事件监听器
绑定事件
所谓的“事件监听器”,指的是使用 addEventListener( )方法为一个元素添加事件,我们又称之为“绑定事件”。
obj.addEventListener(type,fn,false)
obj 是一个 DOM 对象,指的是使用 getElementById( )、getElementsByTagName( )等方法获取的元素节点。
type 是一个字符串,指的是事件类型。如单击事件用 click,鼠标移入用 mouseover 等。一定要注意,这个事件类型是不需要加上“on”前缀的。
fn 是一个函数名,或是一个匿名函数。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>
<script>
window.onload = function(){
var oBtn = document.getElementById("btn");
oBtn.addEventListener("click",alertMsg,false);
function alertMsg(){
alert("JS")
}
//fn 是一个匿名函数,效果相同
// oBtn.addEventListener("click",function(){
// alert("JS")
// },false);
}
</script>
</head>
<body>
<input type="button" id="btn" value="按钮">
</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>
<script>
window.onload = function(){
var oBtn = document.getElementById("btn");
oBtn.addEventListener("click",function(){
alert("1")
},false);
oBtn.addEventListener("click",function(){
alert("2")
},false);
oBtn.addEventListener("click",function(){
alert("3")
},false);
}
</script>
</head>
<body>
<input type="button" id="btn" value="按钮">
</body>
</html>
当我们点击按钮后,浏览器会依次弹出 3 个对话框。也就是说,我们可以使用“事件监听器”这种方式来为同一个元素添加多个相同的事件,而这一点是事件处理器做不到的。
一般情况下,如果是只为元素添加一个事件,下面两种方式其实是等价的。
oBtn.addEventListener("click",function(){...},false);
obj.onclick = function(){...};
<!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>
<script>
window.onload = function(){
var oBtn1 = document.getElementById("btn1");
oBtn1.onclick = function(){
alert("第一次")
}
};
window.onload = function(){
var oBtn2 = document.getElementById("btn2");
oBtn2.onclick = function(){
alert("第二次")
}
};
window.onload = function(){
var oBtn3 = document.getElementById("btn3");
oBtn3.onclick = function(){
alert("第三次")
}
};
</script>
</head>
<body>
<input type="button" id="btn1" value="按钮1">
<input type="button" id="btn2" value="按钮2">
<input type="button" id="btn3" value="按钮3">
</body>
</html>
效果中只有第三个按钮点击后会有弹窗,这是因为 JavaScript 只执行最后一次 window.onload。为了解决这个问题,我们可以使用 addEventListener( )来实现。
<!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>
<script>
window.addEventListener("load",function(){
var oBtn1 = document.getElementById("btn1");
oBtn1.onclick = function(){
alert("第一次")
}
},false);
window.addEventListener("load",function(){
var oBtn2 = document.getElementById("btn2");
oBtn2.onclick = function(){
alert("第二次")
}
},false);
window.addEventListener("load",function(){
var oBtn3 = document.getElementById("btn3");
oBtn3.onclick = function(){
alert("第三次")
}
},false);
</script>
</head>
<body>
<input type="button" id="btn1" value="按钮1">
<input type="button" id="btn2" value="按钮2">
<input type="button" id="btn3" value="按钮3">
</body>
</html>
解绑事件
在 JavaScript 中,我们可以使用 removeEventListener( )方法为元素解绑(或解除)某个事件。解绑事件与绑定事件是功能相反的操作。
<!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>
<script>
window.onload = function(){
var oP = document.getElementById("content");
var oBtn = document.getElementById("btn");
oP.addEventListener("click",changeColor,false);
oBtn.addEventListener("click",remove,false);
function remove(){
alert("解除绑定")
oP.removeEventListener("click",changeColor,false);
}
function changeColor(){
this.style.color = "pink";
}
}
</script>
</head>
<body>
<p id="content">xuexi</p>
<p id="btn">解除</p>
</body>
</html>
点击【解除】之后,再点击 p 元素,发现 p 元素点击事件无效了。
oP.addEventListener("click",changeColor,false);
oP.removeEventListener("click",changeColor,false);
removeEventListener( )只可以解除“事件监听器”添加的事件,不可以解除“事件处理器”添加的事件。如果要解除“事件处理器”添加的事件,我们可以使用“obj.事件名 = null;”来实现,
<!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>
<script>
window.onload = function(){
var oP = document.getElementById("content");
var oBtn = document.getElementById("btn");
oP.onclick = changeColor;
oBtn.addEventListener("click",remove,false);
function remove(){
oP.onclick = null;
}
function changeColor(){
this.style.color = "pink";
}
}
</script>
</head>
<body>
<p id="content">xuexi</p>
<p id="btn">btn</p>
</body>
</html>
event 对象
当一个事件发生的时候,这个事件有关的详细信息都会临时保存到一个指定的地方,这个地方就是 event 对象。每一个事件,都有一个对应的 event 对象。
type
<!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>
<script>
window.onload = function(){
var oBtn = document.getElementById("btn");
oBtn.onclick = function(e){
alert(e.type);
}
}
</script>
</head>
<body>
<input type="button" id="btn" value="按钮">
</body>
</html>
每次调用一个事件的时候,JavaScript 都会默认给这个事件函数加上一个隐藏的参数,这个参数就是 event 对象。一般来说,event 对象是作为事件函数的第 1 个参数传入的。
其实 e 只是一个变量名,它存储的是一个 event 对象。也就是说,e 可以换成其他名字,如 ev、event、a 等,大家可以测试一下。
keyCode
event.keyCode 返回的是一个数值,常用按键对应键码如下:
如果是【Shift】键、【Ctrl】键和【Alt】键,我们不需要通过 keyCode 属性来获取,而可以通过 shiftKey、ctrlKey 和 altKey 属性来获取。
<!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>
<script>
window.onload = function(){
document.onkeydown = function(e){
if(e.shiftKey||e.altKey||e.ctrlKey){
alert("该键被禁用");
}
}
}
</script>
</head>
<body>
<p>
一杯茶,一套题,从早到晚搞学习。
</p>
</body>
</html>
e.keyCode 返回的是一个数字,而 e.shiftKey、e.ctrlKey、e.altKey 返回的都是布尔值(true或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>
<script>
window.onload = function(){
var oSpan = document.getElementsByTagName("span")[1];
window.addEventListener("keydown",function(e){
if(e.keyCode == 38 || e.keyCode == 87){
oSpan.innerHTML = "up";
}else if(e.keyCode == 39 || e.keyCode == 68){
oSpan.innerHTML = "right";
}else if(e.keyCode == 40 || e.keyCode == 83){
oSpan.innerHTML = "down";
}else if(e.keyCode == 37 || e.keyCode == 65){
oSpan.innerHTML = "left";
}else{
oSpan.innerHTML = "";
}},false);
}
</script>
</head>
<body>
<div>你控制的方向是:<span style="color:aqua;"></span></div>
<div>你控制的方向是:<span style="color:aqua;"></span></div>
</body>
</html>
this
在事件操作中,可以这样理解:哪个 DOM 对象(元素节点)调用了 this 所在的函数,那么 this 指向的就是哪个 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>
<script>
window.onload = function(){
var oDiv = document.getElementsByTagName("div")[0];
var oP = document.getElementsByTagName("p")[0];
oDiv.onclick = changeColor;
oP.onclick = changeColor;
function changeColor(){
this.style.color = "blue";
}
}
</script>
</head>
<body>
<div>第一个元素</div>
<p>第二个元素</p>
</body>
</html>
在事件函数中,如果想要使用当前的元素节点,我们应该尽量使用 this 来代替oBtn、oLi[i] 等写法。