JS 事件

《JavaScript高级程序设计》读书笔记

事件流

描述了页面接收事件的顺序。事件捕获——目标阶段——事件冒泡

事件处理程序

HTML事件处理程序

  <form method="post"> 
    <input type="text" name="userName" value="" />
    <input type="button" value="输出" onclick="console.log(userName.value)"/>
  </form>
  <!-- 
    事件处理程序对应的函数等价于:
    function() {
      with(document) {
        with(this.form) {
          with(this) {
            // 属性值
          }
        }
      }
    }
   -->

DOM0 事件处理程序

一个函数赋值给(DOM元素的)一个事件处理程序属性。

let btn = document.getElementById('myBtn');
btn.onclick = funciton() {
    console.log(this.id); // 'myBtn' this引用元素本身
}
btn.onclick = null; // 移除事件处理程序

DOM2 事件处理程序

  • addEventListener()
  • removeEventListener()

接收3个参数:事件名、事件处理函数和一个布尔值(true表示在捕获阶段调用,false默认表示在冒泡阶段调用处理程序)

let btn = document.getElementById("myBtn");
let handler = function() {
    console.log(this.id);
}
btn.addEventListener("click", handler, false);
btn.removeEventListener("click",handler, false); // 移除

事件对象

所有相关信息都会被收集并存储在一个名为event 的对象中。

DOM 事件对象

event 对象是传给事件处理程序的唯一参数。

let btn = document.getElementById("myBtn");
btn.onclick = function(event) {
    console.log(event.type); // "click"
};
btn.addEventListener("click", (event) => {
    console.log(event.type); // "click"
}, false);

// HTML中
// <input type="button" value="Click Me" onclick="console.log(event.type)">

所有事件对象都会包含下表列出的这些公共属性和方法:

属性/方法说明
bubbles布尔值 只读 表示事件是否冒泡
cancelable布尔值 只读 表示是否可以取消事件的默认行为
currentTarget元素 只读 当前事件处理程序所在的元素(this对象始终等于这个)
defaultPrevented布尔值 只读 true 表示已经调用 preventDefault()方法( DOM3 Events 中新增)
detail整数 只读 事件相关的其他信息
eventPhase整数 只读 表示调用事件处理程序的阶段: 1 代表捕获阶段, 2 代表到达目标, 3 代表冒泡阶段
preventDefault()函数 只读 用于取消事件的默认行为。只有 cancelable 为 true 才可以调用这个方法
stopImmediatePropagation()函数 只读 用于取消所有后续事件捕获或事件冒泡,并阻止调用任何后续事件处理程序( DOM3 Events 中新增)
stopPropagation()函数 只读 用于取消所有后续事件捕获或事件冒泡。只有 bubbles为 true 才可以调用这个方法。
target元素 只读 事件目标(如果事件处理程序直接添加在了意图的目标,则this、currentTarget 和 target 三者相同)
trusted布尔值 只读 true 表示事件是由浏览器生成的。 false 表示事件是开发者通过 JavaScript 创建的( DOM3 Events 中新增)
type字符串 只读 被触发的事件类型
ViewAbstractView 只读 与事件相关的抽象视图。等于事件所发生的 window 对象

事件类型

  • 用户界面事件( UIEvent):涉及与 BOM 交互的通用浏览器事件。
  • 焦点事件( FocusEvent):在元素获得和失去焦点时触发。
  • 鼠标事件( MouseEvent):使用鼠标在页面上执行某些操作时触发。
  • 滚轮事件( WheelEvent):使用鼠标滚轮(或类似设备)时触发。
  • 输入事件( InputEvent):向文档中输入文本时触发。
  • 键盘事件( KeyboardEvent):使用键盘在页面上执行某些操作时触发。
  • 合成事件( CompositionEvent):在使用某种 IME( Input Method Editor,输入法编辑器)输入字符时触发。

用户界面事件

  • load:在 window 上当页面加载完成后触发,在窗套( <frameset>)上当所有窗格( <frame>)都加载完成后触发,在<img>元素上当图片加载完成后触发,在<object>元素上当相应对象加载完成后触发。
  • unload:在 window 上当页面完全卸载后触发,在窗套上当所有窗格都卸载完成后触发,在<object>元素上当相应对象卸载完成后触发。
  • abort:在<object>元素上当相应对象加载完成前被用户提前终止下载时触发。
  • error:在 window 上当 JavaScript 报错时触发,在<img>元素上当无法加载指定图片时触发,在<object>元素上当无法加载相应对象时触发,在窗套上当一个或多个窗格无法完成加载时触发。
  • select:在文本框( <input>或 textarea)上当用户选择了一个或多个字符时触发。
  • resize:在 window 或窗格上当窗口或窗格被缩放时触发。
  • scroll:当用户滚动包含滚动条的元素时在元素上触发。 <body>元素包含已加载页面的滚动条。大多数 HTML 事件与 window 对象和表单控件有关。

1. load 事件

js 方式:

window.addEventListener("load", (event) => {
    console.log("Loaded!");
});

 指定 load 事件处理程序的方式:

<body onload="console.log('Loaded!')">

图片也会出发load事件:

window.addEventListener("load", () => {
    let image = document.createElement("img");
    image.addEventListener("load", (event) => {
        console.log(event.target.src);
    });
    document.body.appendChild(image);
    image.src = "smile.gif";
});

2. unload 事件

一般是在从一个页面导航到另一个页面时触发,最常用于清理引用,以避免内存泄漏。

window.addEventListener("unload", (event) => {
    console.log("Unloaded!");
});
<body onunload="console.log('Unloaded!')">

3. resize 事件

window.addEventListener("resize", (event) => {
    console.log("Resized");
});

4. scroll 事件

window.addEventListener("scroll", (event) => {
    if (document.compatMode == "CSS1Compat") {
        console.log(document.documentElement.scrollTop);
    } else {
        console.log(document.body.scrollTop);
    }
});

焦点事件

  • blur:当元素失去焦点时触发。这个事件不冒泡,所有浏览器都支持。
  • focus:当元素获得焦点时触发。这个事件不冒泡,所有浏览器都支持。
  • focusin:当元素获得焦点时触发。这个事件是 focus 的冒泡版。
  • focusout:当元素失去焦点时触发。冒泡版。

鼠标和滚轮事件

  • click:在用户单击鼠标主键(通常是左键)或按键盘回车键时触发
  • dblclick:在用户双击鼠标主键(通常是左键)时触发。
  • mousedown:在用户按下任意鼠标键时触发。这个事件不能通过键盘触发。
  • mouseenter:在用户把鼠标光标从元素外部移到元素内部时触发。这个事件不冒泡,也不会在光标经过后代元素时触发。
  • mouseleave:在用户把鼠标光标从元素内部移到元素外部时触发。这个事件不冒泡,也不会在光标经过后代元素时触发。
  • mousemove:在鼠标光标在元素上移动时反复触发。这个事件不能通过键盘触发。
  • mouseout:在用户把鼠标光标从一个元素移到另一个元素上时触发。移到的元素可以是原始元素的外部元素,也可以是原始元素的子元素。这个事件不能通过键盘触发。
  • mouseover:在用户把鼠标光标从元素外部移到元素内部时触发。这个事件不能通过键盘触发。
  • mouseup:在用户释放鼠标键时触发。这个事件不能通过键盘触发。

1. 客户端坐标(clientX、clientY)

事件发生时鼠标光标在视口中的坐标。

let div = document.getElementById("myDiv");
div.addEventListener("click", (event) => {
    console.log(`Client coordinates: ${event.clientX}, ${event.clientY}`);
});

2. 页面坐标(pageX、pageY)

3. 屏幕坐标(screenX、screenY)

4. 修饰键

  • shiftKey
  • ctrlKey
  • altKey
  • metaKey
document.addEventListener("click", (event) => {
    let keys = new Array();
    if (event.shiftKey) {
        keys.push("shift");
    }
    if (event.ctrlKey) {
        keys.push("ctrl");
    }
    if (event.altKey) {
        keys.push("alt");
    }
    if (event.metaKey) {
        keys.push("meta");
    }
    console.log("Keys: " + keys.join(","));
});

5. 相关元素(relatedTarget)

只有在mouseover 和 mouseout 事件发生时才包含值。

let EventUtil = {
    // 其他代码
    getRelatedTarget: function(event) {
        if (event.relatedTarget) {
            return event.relatedTarget;
        } else if (event.toElement) {
            return event.toElement;
        } else if (event.fromElement) {
            return event.fromElement;
        } else {
            return null;
        }
    },
    // 其他代码
};

let div = document.getElementById("myDiv");
div.addEventListener("mouseout", (event) => {
    let target = event.target;
    let relatedTarget = EventUtil.getRelatedTarget(event);
    console.log(`Moused out of ${target.tagName} to ${relatedTarget.tagName}`);
});

6. 鼠标按键(button)

返回一个值,代表用户按下并触发了事件的鼠标按键。

  • 0:主按键,通常指鼠标左键或默认值

  • 1:辅助按键,通常指鼠标滚轮中键

  • 2:次按键,通常指鼠标右键

7. 额外事件信息(detail)

提供当前点击数

8. mousewheel 事件

在用户使用鼠标滚轮时触发。每次间距120。

document.addEventListener("mousewheel", (event) => {
    console.log(event.wheelDelta);
});

9. 触摸屏设备

  • 不支持 dblclick 事件。双击浏览器窗口可以放大,但没有办法覆盖这个行为。
  • 单指点触屏幕上的可点击元素会触发 mousemove 事件。如果操作会导致内容变化,则不会再触发其他事件。如果屏幕上没有变化,则会相继触发 mousedown、 mouseup 和 click 事件。点触不可点击的元素不会触发事件。可点击元素是指点击时有默认动作的元素(如链接)或指定了 onclick 事件处理程序的元素。
  • mousemove 事件也会触发 mouseover 和 mouseout 事件。
  • 双指点触屏幕并滑动导致页面滚动时会触发 mousewheel 和 scroll 事件。

键盘与输入事件

  • keydown,用户按下键盘上某个键时触发,而且持续按住会重复触发。
  • keypress,用户按下键盘上某个键并产生字符时触发,而且持续按住会重复触发。 Esc 键也会触发这个事件。 DOM3 Events 废弃了 keypress 事件,而推荐 textInput 事件。
  • keyup,用户释放键盘上某个键时触发。

键盘事件支持与鼠标事件相同的修饰键。

1. 键码(keyCode)

键码表

2. 字符编码

只有在keypress 事件触发时,event.charCode/event.keyCode(早期)。

String.fromCharCode() 方法编码转化为字符。

3. DOM3 的变化

key:等于文本字符,在按下非字符键时为键名

textInput事件:在字符被输入到可编辑区域时触发。

document.addEventListener('textInput',e => console.log(e.data))

合成事件

compositionstart:在IME的文本合成系统打开时触发,表示输入即将开始。例如,当用户使用拼音输入法开始输入汉字时,这个事件就会被触发。

compositionupdate:在新字符插入输入阶段时触发

compositionend:在IME文本合成系统关闭时触发,表示恢复正常键盘输入

HTML5 事件

1. beforeunload 事件

在页面即将从浏览器中卸载时触发。弹出一个确认框,确认是否关闭页面。

window.addEventListener('beforeunload', (event) => {
  // Cancel the event as stated by the standard.
  event.preventDefault();
  // Chrome requires returnValue to be set.
  event.returnValue = '';
});

2. DOMContentLoaded 事件

当初始的 HTML 文档被完全加载和解析完成之后,**DOMContentLoaded **事件被触发,而无需等待样式表、图像和子框架的完全加载。始终在load 事件之前触发

document.addEventListener('DOMContentLoaded',function(){
    console.log('3 seconds passed');
});

3. readystatechange 事件

当文档的 readyState 属性发生改变时,会触发 readystatechange 事件。

可能具有属性:

  • uninitialized:对象存在并尚未初始化
  • loading:对象正在加载数据
  • loaded:对象已经加载完数据
  • interactive:对象可以交互,但尚未加载完成
  • complete:对象加载完成

5. pageshow 与 pagehide 事件

往返缓存:使用浏览器后退/前进按钮操作的缓存

paegshow:无论是否来自缓存,都会触发该事件

pagehide:在页面从浏览器卸载后触发

都带有persisted 属性,如果在往返缓存中为ture,否则为false。

6. hashchange 事件

在URL 散列值发生变化时触发

设备事件

用于确定用户使用设备的方式

1. orientationchange 事件

判断用户设备是处于垂直模式还是水平模式。0 表示垂直模式,90 表示左转水平模式,-90 表示右转水平模式。

2. deviceorientation 事件

获取移动设备方向和动作数据。主要是以下5个属性:

  • alpha:0~360 范围内的浮点值,表示围绕z轴旋转时y轴的度数(左右转)
  • beta:-180~180 范围内的浮点值,表示围绕x轴旋转时z轴的度数(前后转)
  • gamma:-90~90 范围内的浮点值,表示围绕y轴旋转时z轴的度数(扭转)
  • absolute:布尔值,表示设备是否返回绝对值
  • compassCalibrated:布尔值,表示设备的指南针是否正确校准

3. devicemotion 事件

用于提示设备实际上在移动,而不仅仅时改变了朝向。例如:可以用来确认设备正在掉落或者正拿在一个行走的人手里。包含如下额外属性:

acceleration:对象,包含x、y和z 属性,反映不考虑重力情况下各个维度的加速信息。

accelerationIncludingGravity:对象,包含x、y和z 属性,反映各个维度的加速信息,包含z 轴自然重力加速度。

interval:毫秒,距离下次触发devicemotion 事件的时间。

rotationRate:对象,包含alpha、beta和gamma 属性,表示设备朝向。

触摸及手势事件

1. 触摸事件

  • touchstart:手指放到屏幕上时触发
  • touchmove:手指在屏幕上滑动时连续触发
  • touchend:手指从屏幕上移开时触发
  • touchcancel:系统停止跟踪触摸时触发

除了包含那些公共的DOM属性,还提供了以下3个属性用于跟踪触点:

  • touches:Touch 对象数组,表示当前屏幕上的每个触点
  • targetTouches:Touch 对象数组,表示特定于事件目标的触点
  • changedTouches:Touch 对象数组,表示自上次用户动作之后变化的触点

每个Touch 对象都包含下列属性:

  • clientX:触点在视口中的x 坐标
  • clientY:触点在视口中的y 坐标
  • identifier:触点ID
  • pageX:触点在页面上的x坐标
  • pageY:触点在页面上的y坐标
  • screenX:触点在屏幕上的x坐标
  • screenY:触点在屏幕上的y坐标
  • target:触摸事件的事件目标

2. 手势事件

会在两个手指触碰屏幕且相对距离或旋转角度变化时触发。只有两个手指同时接触事件接受者时,才会触发。

  • gesturestart:一个手指已经放在屏幕上,再把另一个手指放到屏幕上时触发
  • gesturechange:任何一个手指在屏幕上的位置发生变化时触发
  • gestureend:其中一个手指离开屏幕时触发

新增两个属性:

rotation:表示手指变化旋转的度数,负值表示逆时针旋转,正值表示顺时针

scale:表示两指之间距离变化的程度。开始值为1

内存与性能

1. 事件委托

利用事件冒泡,使用一个事件处理程序来管理一种类型的事件。

  <ul id="myLinks">
    <li id="a">aaa</li>
    <li id="b">bbb</li>
  </ul>

let item1 = document.getElementById("a")
let item2 = document.getElementById("b")
item1.addEventListener("click" ,e=>console.log(e))
item2.addEventListener("click" ,e=>console.log(e))
// 优化后
let list = document.getElementById("myLinks");
list.addEventListener('click',e=>{
  let target = e.target;
  switch(target.id){
    case 'a':
      console.log(1);
      break;
    case 'b':
      console.log(2);
      break;
  }
})

2. 删除事件处理程序

即使删除不用的事件处理程序。

模拟事件

document.createEvent() 方法 创建一个event对象,接受一个参数:

  • UIEvents:通过用户界面事件
  • MouseEvents:通过鼠标事件
  • HTMLEvents:通过HTML事件

dispatchEvent() 方法触发事件

1. 模拟鼠标事件

let btn = document.getElementById("myBtn");
// 创建event 对象
let event = document.createEvent("MouseEvents");
// 初始化event 对象
event.initMouseEvent("click", true, true, document.defaultView, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
btn.dispatchEvent(event);

createEvent() 返回一个event 对象,该对象有一个initMouseEvent() 方法,接受15个参数:

  • type:要触发的事件类型
  • bubbles:表示事件是否冒泡。
  • cancelable(布尔值):表示事件是否可以取消
  • view:与事件关联的视图
  • detail(整数):关于事件的额外信息。
  • screenX(整数):事件相对于屏幕的x 坐标
  • screenY:事件相对于屏幕的y 坐标
  • clientX:事件相对与视口的x坐标
  • clientY:事件相对于视口的y坐标
  • ctrlkey(布尔值):表示是否按下Ctrl键,默认false
  • altkey(布尔值):是否按下Alt键
  • shiftkey
  • metakey
  • button(整数):表示按下了那个按钮。默认0
  • relatedTarget(对象):与事件相关的对象

2. 模拟键盘事件

传入参数:KeyboardEvent

initKeyboardEvent() 方法参数:

  • type
  • bubbles
  • cancelable
  • view
  • key(字符串):按下按键的字符串代码
  • location(整数):按下按键的位置
  • modifiers(字符串):空格分隔的修饰键列表
  • repeat(整数):连续按了这个键多少次

3. 模拟其他事件

let event = document.createEvent("HTMLEvents");
event.initEvent("focus", true, false);
target.dispatchEvent(event);

4. 自定义DOM 事件

自定义事件不会触发原生DOM 事件,但可以让开发者定义自己的事件。

4个参数:

  • type
  • bubbles
  • cancelable
  • detail
let div = document.getElementById("myDiv"), event;
div.addEventListener("myevent", event =>{
  console.log('my div' + event.detail);
});
document.addEventListener("myevent", event =>{
  console.log('document' + event.detail);
});
if(document.implementation.hasFeature("CustomEvents", "3.0")){
  event.document.createEvent("CustomEvent");
  event.initCustomEvent("myevent", true, false, "hellow world");
  div.dispatchEvent(event);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞天巨兽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值