查阅更多事件方式:

https://developer.mozilla.org/zh-CN/docs/Web/Events
或者查看元素的属性(属性中onxxx就是元素拥有的事件行为)

一、常用的事件行为

事件是元素天生自带的默认操作行为

  1. 不论我们是否给其绑定了方法,当我们操作的时候,也会把对应的事件触发

事件绑定是给元素的某个行为绑定一个方法

  1. 目的是当事件行为触发的时候,可以做一些事情

1. 鼠标事件

click 点击(移动端 click 被识别为单击)

  1. dblclick 双击
  2. mousedown 鼠标按下
  3. mouseup 鼠标抬起
  4. mousemove 鼠标移动
  5. mouseover 鼠标滑过
  6. mouseout 鼠标滑出
  7. mouseenter 鼠标进入
  8. mouseleave 鼠标离开
  9. mousewhell 鼠标滚轮滚动

2. 键盘事件

key…

  1. keydown 按下某个键
  2. keyup 抬起某个键
  3. keypress 除 shift / Fn / CapsLock 键以外,其他键按住(连续触发)

键盘码.png

3. 移动端手指事件

单手指事件模型 Touch

  1. touchstart 手指按下
  2. touchmove 手指移动
  3. touchend 手指松开
  4. touchcancel 操作取消(一般应用于非正常状态下操作结束)

多手指事件模型 Gestrue

  1. gestruestart
  2. gesturechange / gestrueundate
  3. gestureend
  4. gesturecancel

4. 表单元素常用事件

  1. focus 获取焦点
  2. blur 失去焦点
  3. change 内容改变

5. 音视频常用事件

  1. canplay 可以播放(资源没有加载完,播放中可能会卡顿)
  2. canplaythrough 可以播放(资源已经加载完,播放中不会卡顿)
  3. play 开始播放
  4. playing 播放中
  5. pause 暂停播放

6. 其他常用事件

  1. load 资源加载完
  2. unload 资源卸载
  3. beforeunload 当前页面关闭之前
  4. error 资源加载失败
  5. scroll 滚动事件
  6. readystatechange AJAX请求状态改变事件
  7. contextmenu 鼠标右键触发

二、DOM 0级事件

dom 0级事件绑定: dom 0级事件绑定的原理:给元素的私有属性赋值,当事件触发,浏览器会帮我们把赋的值执行,但是这样也导致 “只能给当前元素某一个事件行为绑定一个方法”

  1. 元素.on事件行为=function(){}
  2. box.onclick = function () {
  3. console.log('哈哈哈~~');
  4. }
  5. box.onclick = function () {
  6. console.log('呵呵呵~~');
  7. }
  8. box.onclick = function () {
  9. console.log('哈哈哈~~');
  10. // 移除事件绑定:DOM0 直接赋值为 null 即可
  11. box.onclick = null;
  12. }

三、DOM 2级事件

dom 2级事件绑定: dom 2级事件绑定的原理:基于原型链查找机制,找到 EventTarget.prototype 上的方法并且执行,此方法执行,会把给当前元素某个事件行为绑定的所有方法,存放到浏览器默认的事件池中(绑定几个方法,会向事件池存储几个),当事件行为触发,会把事件池中存储的对应方法,依次按照顺序执行 “给当前元素某一个事件行为绑定多个不同方法”

事件池.png

  1. 元素.addEventListener(事件行为,function(){},true/false)
  2. IE6~8中:元素.attachEvent('on事件行为',function(){})
  3. box.addEventListener('click', function () {
  4. console.log('哈哈哈~~');
  5. }, false);
  6. box.addEventListener('click', function () {
  7. console.log('呵呵呵~~');
  8. }, false);
  9. function fn() {
  10. console.log('哈哈哈~~');
  11. // 移除事件绑定:从事件池中移除,所以需要指定好事件类型、方法等信息(要和绑定的时候一样才可以移除)
  12. box.removeEventListener('click', fn, false);
  13. }
  14. box.addEventListener('click', fn, false);
  1. dom 2级事件绑定的时候我们一般都采用实名函数
  2. 目的:这样可以基于实名函数去移除事件绑定
  3. 基于 addEventListener 向事件池增加方法,存在去重机制:“同一个元素,同一个事件类型,在事件池只能存储一遍这个方法,不能重复存储”
  4. dom 0级事件和 dom 2级事件可以混在一起用:执行的顺序以绑定的顺序为主
  1. box.addEventListener('click', function () {
  2. console.log('哔咔哔咔~~');
  3. });
  4. box.onclick = function () {
  5. console.log('哇咔咔~~');
  6. }
  7. box.addEventListener('click', function () {
  8. console.log('call~~');
  9. });
  1. dom 0级事件中能做的事件行为,dom 2级事件都支持,dom 0级事件不一定能处理绑定,例如:transitionend、DOMContentLoaded…
  1. window.addEventListener('load', function () {
  2. // 所有资源都加载完成触发
  3. console.log('LOAD');
  4. });
  5. window.addEventListener('DOMContentLoaded', function () {
  6. // 只要DOM结构加载完就会触发
  7. console.log('DOMContentLoaded');
  8. });
  9. // $(document).ready(function(){})
  10. $(function () {
  11. // JQ 中的这个处理(DOM 结构加载完触发)采用的就是 DOMContentLoaded 事件,并且依托 DOM2 事件绑定来处理,所以同一个页面中,此操作可以被使用多次
  12. });
  13. $(function () {
  14. }); */
  15. // JQ 中的事件绑定采用的都是 DOM2 事件绑定,例如:on / off / one

练习题:window.onload VS $(document).ready()

  1. 1.$(document).ready() 采用的是 DOM2 事件绑定,监听的是 DOMContentLoaded 这个事件,所以只要DOM 结构加载完成就会被触发执行,而且同一个页面中可以使用多次(绑定不同的方法,因为基于 DOM2 事件池绑定机制完成的)
  2. window.onload 必须等待所有资源都加载完成才会被触发执行,采用 DOM0 事件绑定,同一个页面只能绑定一次(一个方法),想绑定多个也需要改为 window.addEventListener(‘load’, function () {})DOM2 绑定方式

三、给元素的事件行为绑定方法

给元素的事件行为绑定方法,当事件行为触发方法会被执行,不仅被执行,而且还会把当前操作的相关信息传递给这个函数 =》事件对象

  1. 如果是鼠标操作:获取的是 MouseEvent 类的实例 =》 鼠标事件对象

    鼠标事件对象 -> MOuseEvent.prototoye -> UIEvent.prototype ->Event.prototype -> Object.prototype

  2. 如果是键盘操作:获取的是KeyboardEvent类的实例 =》 键盘事件对象
  3. 除了以上还有:普通事件对象(Event)、手指事件对象(TouchEvent)等

事件对象

  1. box.onclick = function (ev) {
  2. // 鼠标事件对象
  3. // clientX / clientY:当前鼠标触发点距离当前窗口左上角的X / Y轴坐标
  4. // pageX / pageY:触发点距离当前页面左上角的X / Y轴坐标
  5. // type:触发事件的类型
  6. // target:事件源(操作的是哪个元素,哪个元素就是事件源),在不兼容的浏览器中可以使用srcElement 获取,也代表的是事件源
  7. // preventDefault():用来阻止默认行为的方法,不兼容的浏览器中用 ev.returnValue = false 也可以
  8. 阻止默认行为
  9. // stopPropagation():阻止冒泡传播,不兼容的浏览器中用 ev.cancelBubble = true 也可以阻止默认行为
  10. console.log(ev);
  11. }

四、当事件触发时浏览器会做什么

事件对象和函数以及给谁绑定的事件没啥必然关系,它存储的是当前本次操作的相关信息,操作一次只能有一份信息,所以在那个方法中获取的信息都是一样的,第二次操作,存储的信息会把上一次操作存储的信息替换掉…

每一次事件触发,浏览器都会这样处理一下:

  1. 捕获到当前操作的行为(把操作信息获取到),通过创建 MouseEvent 等类的实例,得到事件对象 EV2. 通知所有绑定的方法(符和执行条件的)开始执行,并且把 EV 当作实参传递给每个方法,所以在每个方法中得到的事件对象其实是一个>
    ……3. 后面再重新触发这个事件行为,会重新获取本次操作的信息,用新的信息替换老的信息,然后继续之前的步骤…
  1. let obj = null;
  2. box.addEventListener('click', function (ev) {
  3. console.log(ev);
  4. obj = ev;
  5. });
  6. box.addEventListener('click', function (ev) {
  7. console.log(ev === obj); // true
  8. });
  9. document.body.onclick = function (ev) {
  10. console.log(ev === obj); // true
  11. }

五、事件传播机制

事件的传播机制: 捕获阶段:从最外层向最里层事件源依次进行查找(目的:是为冒泡阶段事先计算好传播的层级路径) CAPTURING_PHASE:1 目标阶段:当前元素的相关事件行为触发 AT_TARGET:2 冒泡传播:触发当前元素的某一个事件行为,不仅它的这个行为被触发了,而且它所有的祖先元素(一直到window)相关的事件行为都会被依次触发(从内到外的顺序) BUBBLING_PHASE:3 (Event.prototype)

  1. let $ = selector => document.querySelector(selector);
  2. let inner = $('.inner');
  3. let outer = $('.outer');
  4. inner.onclick = function (e) {
  5. console.log('inner 的click事件触发了');
  6. };
  7. outer.onclick = function (e) {
  8. console.log('outer 的click事件触发了');
  9. e.stopPropagation(); // 阻止事件冒泡
  10. };
  11. document.body.onclick = function () {
  12. console.log('body 的click事件被触发了');
  13. };
  14. document.onclick = function () {
  15. console.log('document 的click事件触发了');
  16. };

事件冒泡

事件冒泡:我们点击 inner,inner 的父级元素 outer 的点击事件以及整个文档顶端的 document 的点击事件都会被依次触发。这种从低层级的 html 元素向高层级依次触发事件的现象称为事件冒泡;
取消冒泡:e.stopPropagation() 阻止事件冒泡;
IE 的阻止冒泡: e.cancelBubble = true;

事件传播.png