DOM事件详解
2020-12-13 本文已影响0人
amanohina
绑定事件方法
注册事件的其他方法1
- element.addEventListener()方法
- 参数:
1.事件类型的字符串(直接书写”click”,不需要加 on)
2.事件函数 - 同一个元素可以多次绑定事件监听,同一个事件类型可以注册多个事件函数
- 兼容性问题:不支持 IE9 以下的浏览器
我们把这个绑定方法称之为DOM2级事件绑定
btn.addEventListener("click",function(){
alert("1");
});
// 多次绑定相同的事件类型,事件会根据书写的顺序进行事件的排队
btn.addEventListener("click",clickEvent);
function clickEvent() {
alert("2");
}
注册事件的其他方法2
- element.attachEvent() 方法
- 参数
1.事件类型的字符串(需要加on)
2.事件函数 - 同一个元素可以多次绑定事件监听,同一个事件类型可以注册多个事件函数
-
兼容性问题:只支持IE10及以下的浏览器
在IE10及以下浏览器之外的运行结果
var btn = document.getElementById("btn");
// DOM 2 级事件绑定方式
// 兼容:IE 10 及以下浏览器
// IE8 及以下的浏览器处理事件队列时,会出现顺序错乱
btn.attachEvent("onclick",function () {
alert(3);
});
btn.attachEvent("onclick",clickEvent);
function clickEvent() {
alert(4);
}
IE8及以下浏览器处理事件队列的时候会出现顺序错乱
注册事件兼容写法
- 自定义一个注册事件函数
- 参数:事件源,事件类型(不加on)。事件函数
- IE9及以上的浏览器,使用addEventListener方法
- IE9以下的浏览器,使用attachEvent方法
- 判断浏览器时,不需要判断它的版本,可以检测浏览器能力
- 浏览器能力监测:将某个方法的调用作为if语句的判断条件,如果浏览器认识该方法返回true,否则false
比如:
<script>
var btn = document.getElementById("btn");
// DOM 2 级事件绑定方式
// 调用函数
addEvent(btn,"click",function(){
alert("1")
});
// 自己制作一个兼容所有浏览器的绑定事件的函数
// 参数:事件源,事件类型,事件函数
function addEvent(ele,type,fn){
// 判断,IE 9 及以上和其他浏览器,使用addEVentListener
// IE 9 及以下的浏览器,使用attachEvent
// 浏览器能力监测
if(ele.addEventListener){
ele.addEventListener(type,fn);
}else if(ele.attachEvent){
ele.attachEvent("on"+type,fn);
}
}
</script>
移除事件
移除事件的其他方法1
- element.removeEventListener()方法
- 参数
1.事件类型的字符串(直接书写"click",不需要加on)
2.事件函数引用名 - 注意:没有办法移除一个匿名函数,所以在注册事件时需要单独声明
- 兼容性问题:不支持IE 9 以下的浏览器
移除绑定的语句必须要在绑定事件语句之后进行
<script>
var btn = document.getElementById("btn");
// 绑定事件
// btn.onclick = function(){
// alert(1);
// };
// // 解除绑定方法:
// btn.onclick = null;
// 绑定事件
btn.addEventListener("click",fun);
btn.addEventListener("click",fun2);
function fun2(){
alert(2);
}
function fun(){
alert(1);
}
// 解除绑定
btn.removeEventListener("click",fun);
btn.removeEventListener("click",fun2);
</script>
移除事件的其他方法2
- element.detachEvent() 方法。
- 参数:第一个参数:事件类型的字符串(需要加 on) 第二个参数:事件函数
- 注意:没有办法移除一个匿名函数,所以在注册事件时需要单独声明一个有函数名的事件函数。
- 兼容性问题:只支持 IE10 及以下的浏览器
// 绑定事件
btn.attachEvent("onclick",fun);
btn.attachEvent("onclick",fun2);
// btn.detachEvent("onclick",fun);
function fun(){
alert(2);
}
function fun2(){
alert(3);
}
解除事件兼容写法
- 自定义一个移除事件函数
- 参数:事件源,事件类型(不加 on),事件函数
- IE9 及以上的浏览器,使用 removeEventListener 方法
- IE9 以下的浏览器,使用 detachEvent 方法
- 建议:将自己封装的一些常用函数和方法,放到一个单独的 .js 文件中。
// 兼容所在浏览器的解除绑定事件的函数
// 参数:事件源,事件类型,事件函数
function removeEvent(ele,type,fn){
// 浏览器能力监测
if(ele.removeEventListener){
ele.removeEventListener(type,fn);
}else if(ele.detachEvent){
ele.detachEvent("on"+type,fn);
}
}
将绑定和解除事件兼容的写法封装到js库内,如下:(获取id,绑定事件,解除事件)
// 定义一个获取元素的函数
function my$(id) {
return document.getElementById(id);
}
// DOM 2 级事件绑定方式
// 自己制作一个兼容所有浏览器的绑定事件的函数
// 参数:事件源,事件类型,事件函数
function addEvent(ele, type, fn) {
// IE 9 及以上的浏览器和其他浏览器,使用 addEventListener 方法
// IE 9 以下的浏览器,使用 attachEvent 方法
// 浏览器能力检测
if (ele.addEventListener) {
ele.addEventListener(type, fn);
} else if (ele.attachEvent) {
ele.attachEvent("on" + type, fn);
}
}
// 兼容所有浏览器的 解除绑定事件的函数
// 参数:事件源,事件类型,事件函数
function removeEvent(ele, type, fn) {
// 浏览器能力检测
if (ele.removeEventListener) {
ele.removeEventListener(type, fn);
} else if (ele.detachEvent) {
ele.detachEvent("on" + type, fn);
}
}
DOM事件流
事件流,先捕获,再冒泡<script>
var box1 = document.getElementById("box1");
var box2 = document.getElementById("box2");
var box3 = document.getElementById("box3");
// 添加点击事件
// addEventListener有第三个参数,用来决定事件流的方向
// 参数值是布尔值,false表示事件流是按照事件冒泡的过程执行的,true表示事件捕获过程
// 参数的默认值是false,默认为时间冒泡过程
box1.addEventListener("click",function(){
console.log(this.id);
});
box2.addEventListener("click",function(){
console.log(this.id);
});
box3.addEventListener("click",function(){
console.log(this.id);
});
box1.addEventListener("click",function(){
console.log(this.id);
},true);
box2.addEventListener("click",function(){
console.log(this.id);
},true);
box3.addEventListener("click",function(){
console.log(this.id);
},true);
// 冒泡过程和捕获过程一起执行是先进行捕获,再进行冒泡
</script>
显而易见,先捕获,再冒泡
事件流的三个阶段
- 第一个阶段:事件捕获
- 第二个阶段:事件执行过程
- 第三个阶段:事件冒泡
- addEventListener()第三个参数为false,事件冒泡
- addEventListener()第三个参数为true,事件捕获
- onclick类型:只能进行事件冒泡过程,没有捕获阶段
- attachEvent()方法:只能进行事件冒泡过程,没有捕获阶段
事件冒泡的应用——事件委托
- 利用事件冒泡,将子级的事件委托给父级加载
- 同时,需要利用事件函数的一个参数e,内部存储的是事件对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
ul {
width: 300px;
border: 1px dashed #f0f;
margin: 50px auto;
font-size: 24px;
line-height: 48px;
list-style: none;
}
li {
padding-left: 20px;
cursor: pointer;
}
</style>
</head>
<body>
<ul id="list">
<li>刘亦菲</li>
<li>杨幂</li>
<li>唐嫣</li>
<li>赵丽颖</li>
<li>刘诗诗</li>
</ul>
<script>
// 让每个 li 被点击后,自己添加特殊的背景色,而其他兄弟不添加
// 以前的思路,获取所有的li标签元素,然后批量添加事件
// 事件委托原理:可以将一些子级的公共类型的事件委托给父级添加,然后在父级内部想办法找到真正触发事件的最底层的事件源
// 获取元素
var list = document.getElementById("list");
var lis = list.children;
// 事件委托的过程,给ul添加点击事件
list.onclick = function(e){
// 内部要想办法找到真正触发事件的li
// 借用事件函数内部的一个参数,e是事件对象
// 只要触发了事件,这时候函数内部他都可以得到一个事件对象,对象中存储了关于事件的一系列数据
// e.target 这个属性记录的就是真正触发的事件的事件源
// 排除其他
for(var i = 0;i<lis.length;i++){
lis[i].style.backgroundColor = "";
}
e.target.style.backgroundColor = "pink";
};
</script>
</body>
</html>
事件对象
- 只要触发了事件,就会有一个对象,内部存储了与事件相关的数据
- e 在低版本浏览器有兼容问题,低版本浏览器用的是window.event
- 事件对象常用的属性:
e.eventPhase ——查看事件触发时所处的阶段
1:捕获阶段
2:目标执行阶段
3:冒泡阶段
e.target ——用于获取触发事件的元素
e.srcElement ——用于获取触发事件的元素,低版本浏览器使用
e.currentTarget——用于获取绑定事件的事件源(事件绑定的事件源是谁)
box1.onclick = function (e) {
// 获取绑定事件的事件源元素
console.log(e.currentTarget);
}
box1就是事件源
e.type——获取事件类型
// 可以将所有给一个元素绑定的事件的事件函数写在一个函数内,通过函数内部的e.type判断走不同的分支
// 避免添加多个函数,占用更多的内存
box1.onmouseover = fn;
box1.onmouseout = fn;
function fn(e){
e = e || window.event;
// 根据事件类型执行不同的代码
switch(e.type){
case "mouseover":
box1.style.backgroundColor = "skyblue";
break;
case "mouseout":
box1.style.backgroundColor = "yellowgreen";
break;
}
}
e.clientX/e.cilentY——所有浏览器都支持,鼠标距离浏览器窗口左上角的距离
e.pageX/e.pageY——IE8以前不支持,鼠标距离整个HTML页面左上顶点的距离
// 事件对象中有一些获取尺寸的属性
box1.onclick = function(e){
// client系列:客户端尺寸,点击的点参考浏览器窗口左上角的距离,跟自己页面的左上角没有关系
console.log(e.clientX);
console.log(e.clientY);
// page系列,html页面尺寸,点击的点参考HTML文档左上角的距离
console.log(e.pageX);
console.log(e.pageY);
事件对象案例:图片跟随鼠标移动而移动
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
#pic {
position: fixed;
}
</style>
</head>
<body>
<img src="images/tianshi.gif" alt="" id="pic">
<script>
// 通过鼠标移动事件给图片添加left和top值
// 获取元素
var pic = document.getElementById("pic");
// 添加鼠标移动事件(给整个文档)
document.onmousemove = function(e){
e = e || window.event;
// 给pic元素css属性赋值
pic.style.left = e.clientX + "px";
pic.style.top = e.clientY + "px";
};
</script>
</body>
</html>
取消默认行为和阻止冒泡(阻止事件传播)
- e.preventDefault() 取消默认行为 ,低版本浏览器不能兼容
- e.returnValue 取消默认行为,低版本浏览器使用
<body>
<a id="link" href="52_图片跟随鼠标移动效果.html">点击</a>
<script>
var link = document.getElementById('link');
link.onclick = function (e) {
e = e || window.event;
alert('hello');
// 普通的方式阻止默认行为
// return false;
// DOM 的方法
// e.preventDefault();
// 低版本浏览器需要使用一个对象的属性
e.returnValue = false;
}
</script>
</body>
- e.stopPropagation(); 阻止冒泡,标准方式
- e.cancelBubble = true; 阻止冒泡,IE 低版本,标准中已废弃
<script>
// 事件冒泡
var box1 = document.getElementById('box1');
var box2 = document.getElementById('box2');
var box3 = document.getElementById('box3');
var array = [box1, box2, box3];
for (var i = 0; i < array.length; i++) {
var box = array[i];
box.onclick = function (e) {
e = e || window.event;
console.log(this.id);
// 阻止事件冒泡
// e.stopPropagation();
// 低版本浏览器使用 属性
e.cancelBubble = true;
}
}
</script>
其他常见事件类型
参考资料: