JavaScript 事件 - 图1

1. 什么是事件?

  • 事件就是一件事情或者一个行为(对于元素来说,它的很多事件都是天生自带的),只要我们去操作这个元素,就会触发这些行为事件就是元素天生自带的行为,我们操作元素,就会触发相关的事件行为

    2. 事件绑定

  • 给元素天生自带的事件行为绑定方法,当事件触发,会把对应的方法执行

  • oBox.onclick=function(){}

    1. DOM0级事件绑定

    [element].onxxx=function(){}

    2. DOM2级事件绑定

    [element].addEventListener(‘xxx’,function(){},false);
    [element].attachEvent(‘onxxx’,function(){}); [IE6~8]

    事件池.png_

    3. 目的

    给当前元素的某个事件绑定方法(不管是基于DOM0还是DOM2),都是为了触发元素的相关行为的时候,能做点事情(也就是把绑定的方法执行);不仅把方法执行了,而且浏览器还给方法传递了一个实参信息值 ==>这个值就是事件对象”

4. 兼容

DOM2事件绑定的兼容 [谷歌 VS IE高版本]
在移除事件绑定的时候,如果移除操作发生在正要执行的方法之前(例如:点击的时候,正要执行FN8,但是在执行FN4的时候,我们把FN8从事件池中移除了),谷歌下是立即移除生效,第一次也不再执行FN8了,而IE是当前本次不生效,下一次点击才生效,第一次点击还是要执行FN8的;
标准 VS IE低版本
标准:addEventListener / removeEventListener
_ _IE低:attachEvent / detachEvent
标准用的是行为名称“click”,而IE低版本使用时前面要加on“onclick

  1. THIS问题 标准浏览器中,行为触发方法执行,方法中的THIS是当前元素本身,IE低版本中THIS指向了WINDOW
  2. 重复问题 标准浏览器中的事件池是默认去重复的,同一个元素的同一个事件行为不能出现相同的绑定方法,但是IE低版本的事件池机制没有这么完善,不能默认去重,也就是可以给同个元素的同个事件绑定相同的方法
  3. 顺序问题 标准浏览器是按照向事件池中存放的顺序依次执行的,而IE低版本是乱序执行的,没有规律IE低版本浏览器出现的所有问题都是由于本身自带的事件池机制不完整导致的

DOM0事件绑定和DOM2事件绑定的区别

  1. 机制不一样 DOM0采用的是给私有属性赋值,所以只能绑定一个方法 DOM2采用的是事件池机制,所以能绑定多个不同的方法
  2. 移除的操作
  3. DOM2事件绑定中增加了一些DOM0无法操作的事件行为,例如:DOMContentLoaded事件(当页面中的HTML结构加载完成就会触发执行)

    3. 元素天生自带的事件

    1. 鼠标事件

    • click:点击 (PC端是点击,移动端的click代表单击[移动端使用click会有300MS延迟的问题])
    • dblclick:双击
    • mouseover:鼠标经过
    • mouseout:鼠标移出
    • mouseenter:鼠标进入
    • mouseleave:鼠标离开
    • mousemove:鼠标移动
    • mousedown:鼠标按下(鼠标左右键都起作用,它是按下即触发,click是按下抬起才会触发,而且是先把down和up触发,才会触发click)
    • mouseup:鼠标抬起
    • mousewheel:鼠标滚轮滚动

      2. 键盘事件

    • keydown:键盘按下

    • keyup:键盘抬起
    • keypress:和keydown类似,只不过keydown返回的是键盘码,keypress返回的是ASCII码值
    • input:由于PC端有实体物理键盘,可以监听到键盘的按下和抬起,但是移动端是虚拟的键盘,所以keydown和keyup在大部分手机上

      3. 表单元素常用的事件

    • focus:获取焦点

    • blur:失去焦点
    • change:内容改变

      4. 其它常用事件

    • load:加载完成

    • unload
    • beforeunload
    • scroll:滚动条滚动事件
    • resize:大小改变事件 window.onresize=function(){} 当浏览器窗口大小发生改变,会触发这个事件,执行对应的事情

5. 移动端手指事件

1. touch:单手指操作

  1. - touchstart:手指按下
  2. - touchmove:手指移动
  3. - touchend:手指离开
  4. - touchcancel:因为意外情况导致手指操作取消

2. gesture:多手指操作

     - gesturestart:手指按下<br />
     - gesturechange:手指改变<br />
     - gestureend:手指离开    

3. H5中的AUDIO/VIDEO音视频事件

     - canplay:可以播放(播放过程中可能出现由于资源没有加载完成,导致的卡顿<br />
     - canplaythrough:资源加载完成,可以正常无障碍播放

4. 事件对象

   在事件触发时,浏览器传递给事件函数的实参;其中包含了本次事件触发的具体信息;_ _

事件对象是用来存储当前本次操作的相关信息,和操作有关,和元素无必然关联 2.当我们基于鼠标或者键盘等操作的时候,浏览器会把本次操作的信息存储起来 (标准浏览器存储到默认的内存中(自己找不到),IE低版本存储到window.event中了), 存储的值是一个对象(堆内存);操作肯定会触发元素的某个行为,也就会把绑定的方法执行, 此时标准浏览器会把之前存储的对象(准确来说是堆内存地址)当做实参传递给每一个执行的方法,所以操作一次,* 即使再多方法中都有EV,但是存储的值都是一个(本次操作信息的对象而已

let box = document.querySelector('.box');
box.onclick = function (e) {
   console.log(e); // MouseEvent e 一般称为事件对象,
   // e.clientX 鼠标点击的位置相对于当前浏览器可视窗口的 左偏移值
   // e.clientY 鼠标点击位置相对于当前浏览器可视窗口的 上偏移值
   // e.pageX 鼠标点击位置相对于 body 左边缘的偏移值
   // e.pageY 鼠标点击位置相对于 body 上边缘的偏移值
   // e.target 触发事件的元素(点击事件中是点击的元素)对象,称为事件源
   // IE 事件触发时把事件信息挂载在 window.event  这个属性上
};
document.onkeydown = function (e) {
   // 键盘事件 KeyboardEvent 
   console.log(e);
   console.log(e.keyCode);
   // e.keyCode 键码:键盘上每个键对应一个键码,当 keydown 事件触发时,
};

5. 默认事件和默认行为

有些元素时由默认行为的,如a标签点击会跳转。

let baidu = document.getElementById('baidu');
// 阻止默认行为:
baidu.onclick = function (e) {
   alert(111);
   e.preventDefault(); // 阻止元素的事件默认行为
   // IE 低版本:e.returnValue = false
   return false; // return false 也可以阻止默认行为
};

6. 事件传播:

let $ = (selector) => document.querySelector(selector);
let outer = $('.outer');
let inner = $('.inner');
let center = $('.center');
document.onclick = function () {
   console.log('document')
};
outer.onclick = function () {
   console.log('outer')
};
inner.onclick = function () {
   console.log('inner')
};
center.onclick = function (e) {
   console.log('center');
   e.stopPropagation();
};
  • 点击 center 会触发 center 的点击事件,同时 inner 和 outer 的以及更高层级的元素的点击事件也会被触发。这种现象称为事件的冒泡机制;
    事件的触发过程:事件的触发分为两个三个阶段:捕获阶段、目标阶段、冒泡阶段。在事件触发时,浏览器先从最外层的元素开始找,一直找到事件源的过程称为捕获阶段,触发事件源绑定事件后开始向上冒泡,依次触发父级元素的该事件;
  • 事件的传播机制.png
  • 元素.onXXX = func… 绑定的事件都是 DOM0 级事件,DOM0 级事件都是绑定在冒泡阶段的。
  • 取消冒泡:e.stopPropagation()
    • IE 低版本:e.cancelBubble = true;
    • 取消冒泡后,事件不会再向上传播;更高层级的元素的对应事件不会触发;

7. onmouseover 和 mouseenter

let $ = selector => document.querySelector(selector);
let inner = $('.inner');
let outer = $('.outer');
  • mouseover
inner.onmouseover = function () {
   console.log('inner over');
};
inner.onmouseout = function () {
   console.log('inner out')
};
outer.onmouseover = function () {
   console.log('outer over')
};
outer.onmouseout = function () {
   console.log('outer out')
};
  • mouseenter
inner.onmousenter = function () {
   console.log('inner enter');
};
inner.onmouseleave = function () {
   console.log('inner leave')
};
outer.onmouseenter = function () {
   console.log('outer enter')
};
outer.onmouseleave = function () {
   console.log('outer leave')
};
  • mouseenter & mouseover 的区别:
  1. over 属于划过事件,从父元素进入子元素,属于离开了父元素,会触发父元素的out事件,然后触发子元素的 over 事件;
  2. enter 属于进入,从父元素进入子元素,不算离开父元素,不会触发父元素的 leave 事件;
  3. enter 和 leave 是阻止了事件冒泡的,而 over 和 out 还存在冒泡传播;
    所以对于父子嵌套的这种情况,使用 over 会触发很多不可控的情况,使用 enter 更加简单。
  4. ENTER 和 OVER 的区别.png

    8. 事件委托

    **利用事件的冒泡传播机制,如果一个容器的后代元素中,很多元素的点击行为(其它事件行为也是)都要做一些处理,此时我们不需要在像以前一样一个个获取一个个的绑定了,我们只需要给容器的CLICK绑定方法即可,这样不管点击的是哪一个后代元素,都会根据冒泡传播的传递机制,把容器的CLICK行为触发,把对应的方法执行,根据事件源, 我们可以知道点击的是谁,从而做不同的事情即可**

    事件委托原理图.png