Js高程十三章事件 未完

事件流

1.事件冒泡 自内向外

//DOM
<!DOCTYPE html> 
<html> 
<head> 
 <title>Event Bubbling Example</title> 
</head> 
<body> 
 <div id="myDiv">Click Me</div> 
</body> 
</html>

执行顺序:在这里插入图片描述
IE5.5 及更早版本中的事件冒泡会跳过<html>元素(从<body>直接跳到 document).
IE9、Firefox、Chrome 和 Safari 则将事件一直冒泡到 window 对象

2.事件捕获 自外向内 不常用因为对老版本浏览器不支持

执行顺序

DOM事件流
因此有两次操作目标的机会捕获和冒泡在这里插入图片描述

事件处理程序on+事件名

HTML事件 耦合度高 不建议

<input type="button" value="Click Me" onclick="alert(event.type)" />
<input type="button" value="Click Me" onclick="alert(this.value)" />

这样指定事件处理程序具有一些独到之处。首先,这样会创建一个封装着元素属性值的函数。这个
函数中有一个局部变量 event,也就是事件对象
使用事件对象例如event.type
通过 event 变量,可以直接访问事件对象
在这里this==事件的目标元素

DOM0,2级事件处理

DOM0

  <input type="button" name="btn1" id="btn" />
  <script>
    let btn = document.getElementById("btn")
    btn.onclick = function () {
      console.log(this.id) //this引用当前元素 用了this就不能用箭头函数 会改变this指向
    } 
  </script>

如果这些代码在页面中位于按钮后面,就有可
能在一段时间内怎么单击都没有反应
可以删除通过 DOM0 级方法指定的事件处理程序

btn.onclick = null

DOM2

  • addEventListener()
  • removeEventListener()
    接受 3 个参数 args[0]事件名 args[1]事件处理函数
    args[2]布尔值true是在捕获阶段处理 false为冒泡处理
    使用 DOM2 级方法添加事件处理程序的主要好处是可以添加多个事件处理程序
    通过 addEventListener()添加的事件处理程序只能使用 removeEventListener()来移除
    且传入的事件处理函数需相同
var btn = document.getElementById("myBtn"); 
var handler = function(){ 
 alert(this.id); 
};
btn.addEventListener("click", handler, false);
btn.removeEventListener("click", handler, false);

IE事件处理 形式与DOM2类似

var btn = document.getElementById("myBtn"); 
btn.attachEvent("onclick", function(){ 
 alert("Clicked");  //在chrome中报错 attachEvent not a function
});

在使用 attachEvent()方法的情况下
事件处理程序会在全局作用域中运行,因此 this 等于 window

var btn = document.getElementById("myBtn"); 
btn.attachEvent("onclick", function(){ 
 alert("Clicked"); 
}); 
btn.attachEvent("onclick", function(){ 
 alert("Hello world!"); 
});

与 DOM方法不同的是,这些事件处理程序不是以添加它们的顺序执行
,而是以相反的顺序被触发 “hello world” "Clicked"

var btn = document.getElementById("myBtn"); 
var handler = function(){ 
 alert("Clicked"); 
}; 
btn.attachEvent("onclick", handler); 
btn.detachEvent("onclick", handler); //可移除事件处理函数

跨浏览器事件处理

要保证处理事件的代码能在大多数浏览器下一致地运行,只需关
注冒泡阶段

    const EventUtil = {
      addHandler: (element, type, handler) => {
        if (element.addEventListener) {
          element.addEventListener(type, handler, false);
        } else if (element.attachEvent) {
          element.attachEvent("on" + type, handler);
        } else {
          element["on" + type] = handler;
        }
      },
      removeHandle: (element, type, handler) => {
        if (element.removeEventListener) {
          element.removeEventListener(type, handler, false);
        } else if (element.detachEvent) {
          element.detachEvent("on" + type, handler);
        } else {
          element["on" + type] = null;
        }
      }
    }
	var btn = document.getElementById("myBtn")
    var handler = () => {
      alert("Clicked")
    }
    EventUtil.addHandler(btn, "click", handler) //使用EventUtil
    EventUtil.removeHandler(btn, "click", handler) //移除

这两个方法首先都会检测传入的元素中是否存在 DOM2 级方法。
如果存在 DOM2 级方法,则使用该方法:
传入事件类型、事件处理程序函数和第三个参数 false(表示冒泡阶段)。
如果存在的是 IE 的方法,
则采取第二种方案。注意,为了在 IE8 及更早版本中运行,此时的事件类型必须加上"on"前缀。
最后一种可能就是使用 DOM0 级方法(在现代浏览器中,应该不会执行这里的代码)。

事件对象

兼容 DOM 的浏览器会将一个 event 对象传入到事件处理程序中。无论指定事件处理程序时使用什
么方法(DOM0 级或 DOM2 级),都会传入 event 对象。

var btn = document.getElementById("myBtn"); 
btn.onclick = function(event){ 
 alert(event.currentTarget === this); //true 
 alert(event.target === this); //true 
};

这个例子检测了 currentTarget 和 target 与 this 的值。由于 click 事件的目标是按钮,因此
这三个值是相等的。如果事件处理程序存在于按钮的父节点中(例如 document.body),那么这些值是
不相同的

document.body.onclick = function(event){ 
 alert(event.currentTarget === document.body); //true 
 alert(this === document.body); //true 
 alert(event.target === document.getElementById("myBtn")); //true 
};

当单击这个例子中的按钮时,this 和 currentTarget 都等于 document.body,因为事件处理程
序是注册到这个元素上的。然而,target 元素却等于按钮元素,因为它是 click 事件真正的目标。由
于按钮上并没有注册事件处理程序,结果 click 事件就冒泡到了 document.body,在那里事件才得到
了处理。
在需要通过一个函数处理多个事件时,可以使用 type 属性。

    var btn = document.getElementById("myBtn");
    var handler = function (event) {
      switch (event.type) {
        case "click":
          alert("Clicked");
          break;
        case "mouseover":
          event.target.style.backgroundColor = "red";
          break;
        case "mouseout":
          event.target.style.backgroundColor = "";
          break;
      }
    };
    btn.onclick = handler;
    btn.onmouseover = handler;
    btn.onmouseout = handler;

要阻止特定事件的默认行为,可以使用 preventDefault()方法。例如,链接的默认行为就是在
被单击时会导航到其 href 特性指定的 URL。

var link = document.getElementById("myLink"); 
link.onclick = function(event){ 
 event.preventDefault(); 
};

事件对象的 eventPhase 属性,可以用来确定事件当前正位于事件流的哪个阶段.
如果是在捕获阶段调用的事件处理程序,那么 eventPhase 等于 1;
如果事件处理程序处于目标对象上,则 eventPhase 等于 2;
如果是在冒泡阶段调用的事件处理程序,eventPhase 等于 3。

var btn = document.getElementById("myBtn"); 
btn.onclick = function(event){ 
 alert(event.eventPhase); //2 
}; 
document.body.addEventListener("click", function(event){ 
 alert(event.eventPhase); //1 
}, true); 
document.body.onclick = function(event){ 
 alert(event.eventPhase); //3 
};
// 1 2 3

首先执行的事件处理程序是在捕获阶段触发的添加到 document.body
中的那一个,结果会弹出一个警告框显示表示 eventPhase 的 1。接着,会触发在按钮上注册的事件处
理程序,此时的 eventPhase 值为 2。最后一个被触发的事件处理程序,是在冒泡阶段执行的添加到
document.body 上的那一个,显示 eventPhase 的值为 3。而当 eventPhase 等于 2 时,this、target
和 currentTarget 始终都是相等的

IE事件对象
在使用 DOM0 级方法添加事件处理程序时,event 对象作为 window 对象的一个属性存在。
因为事件处理程序的作用域是根据指定它的方式来确定的,所以不能认为 this 会始终等于事件目
标。故而,最好还是使用 event.srcElement 比较保险

var btn = document.getElementById("myBtn"); 
btn.onclick = function(){ 
 alert(window.event.srcElement === this); //true 
}; 
btn.attachEvent("onclick", function(event){ 
 alert(event.srcElement === this); //false 
});

跨浏览器事件对象

    var EventUtil = {
      addHandler: function (element, type, handler) {
        //function
      },
      getEvent: function (event) {
        return event ? event : window.event;		//返回对event对象引用
      },
      getTarget: function (event) {
        return event.target || event.srcElement;		//返回事件目标
      },
      preventDefault: function (event) {		//取消事件默认行为
        if (event.preventDefault) {
          event.preventDefault();
        } else {
          event.returnValue = false;
        }
      },
      removeHandler: function (element, type, handler) {
        //function
      },
      stopPropagation: function (event) {		//阻止事件流
        if (event.stopPropagation) {
          event.stopPropagation();
        } else {
          event.cancelBubble = true;
        }
      }
    };

事件类型

DOM3级规定:ui focus blur click …
检测

var isSupported = document.implementation.hasFeature("UIEvent", "3.0");

focus blur不冒泡
当焦点从页面中的一个元素移动到另一个元素,会依次触发下列事件:
(1) focusout 在失去焦点的元素上触发;
(2) focusin 在获得焦点的元素上触发;
(3) blur 在失去焦点的元素上触发;
(4) DOMFocusOut 在失去焦点的元素上触发;
(5) focus 在获得焦点的元素上触发;
(6) DOMFocusIn 在获得焦点的元素上触发。

鼠标事件顺序
(1) mousedown
(2) mouseup
(3) click
(4) mousedown
(5) mouseup
(6) click
(7) dblclick
鼠标事件中的对象会保存两个属性clientX和clientY
可以获取到鼠标事件发生的位置 分别表示离视口的上左距离
页面坐标位置这两个属性表示鼠标光标在页面
中的位置,因此坐标是从页面本身而非视口的左边和顶边计算的。
屏幕坐标位置相对于整个电脑屏幕的位置。而通
过 screenX 和 screenY 属性就可以确定鼠标事件发生时鼠标指针相对于整个屏幕的坐标信息

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值