JavaScript 教程 - part 3
1. 事件
1.1 EventTarget 接口
事件本质是程序各个组成部分之间的一种通信方式。DOM的事件触发都定义在EventTarget接口当中,所有节点对象都部署了这个接口
该接口主要提供了三个实例方法:
- addEventListener 绑定事件的监听函数
- removeEventListener 移除事件的监听函数
- dispatchEvent 触发事件
1.1.1 EventTarget.addEventListener()
- 用于在当前节点或对象上,定义一个特定的时间的监听函数,一旦这个事件发生,就会执行监听函数
- 没有返回值
target.addEventListener(type, listener, [useCapture])
- type 事件名称
- listener 监听函数 事件发生,就调用这个监听函数
- useCapture 表示监听函数是否在捕获阶段触发,默认为false (只在冒泡阶段被触发)
- 捕获指的是事件从最外层开始发生,直到最具体的元素
- 冒泡指从最内层开始发生
- 第三个参数 – 是个属性配置对象,即除了useCapture 你还可以配置很多其他属性的
- capture 是否在捕获阶段触发监听函数
- once 是否只触发一次,然后就自动移除
- passive 表示监听函数不会调用事件的preventDefault方法,如果监听函数调用了,浏览器就会忽略这个要求,并在监控台上输出一行警告
function hello() {
console.log('Hello world');
}
var button = document.getElementById('btn');
button.addEventListener('click', hello, false);
1.1.2 EventTarget.removeEventListener()
用来移除addEventListener方法添加的事件监听函数,该方法没有返回值。
- removeEnventListener方法移除的监听函数必须是addEventListener方法已经添加过得,而且必须在同一个元素节点上,否则无效
1.1.3 EventTarget.dispatchEvent()
- 在当前节点触发指定事件,从而触发监听函数的执行 返回一个布尔值
- 只要有一个监听函数调用了
Event.preventDefault()
,返回值为false,否则为true
para.addEventListener('click', hello, false);
var event = new Event('click');
para.dispatchEvent(event);
1.2 事件模型
这一部分想要解决的问题是JS作为使用事件驱动编程模式(event-driven)的编程语言,是怎么样给事件绑定监听函数的。
1.2.1 绑定监听函数
1.2.1.1 使用html on属性
HTML允许在元素属性当中,直接定义某些事件的监听代码
<body onload="doSomething()">
- 元素的监听属性,都是on加上事件名
- 属性的值为将要执行的代码,单单函数名是不被允许的
- 该种方式的监听代码,只会在冒泡阶段被触发
// 先输出1 再输出2
<div onClick="console.log(2)">
<button onClick="console.log(1)">点击</button>
</div>
1.2.1.2 使用元素节点的事件属性
- 也是只可以在冒泡阶段进行触发
window.onload = doSomething;
div.onclick = function (event) {
console.log('触发事件');
};
1.2.1.3 使用addEventListener()
用来为该节点定义事件的监听函数
1.2.2 事件的传播
事件发生后,会在子元素和父元素之间进行传播,分为以下几个阶段:
- 从window对象传导到目标节点(上层传到底层),成为捕获阶段(capture phase)
- 在目标节点上触发,称为目标阶段
- 从目标节点传导会window对象,称为冒泡阶段 - bubbling phase
这种三阶段的传播模型,使得同一个事件会在多个节点上触发。
<div>
<p>点击</p>
</div>
var phases = {
1: 'capture',
2: 'target',
3: 'bubble'
};
var div = document.querySelector('div');
var p = document.querySelector('p');
div.addEventListener('click', callback, true);
p.addEventListener('click', callback, true);
div.addEventListener('click', callback, false);
p.addEventListener('click', callback, false);
function callback(event) {
var tag = event.currentTarget.tagName;
var phase = phases[event.eventPhase];
console.log("Tag: '" + tag + "'. EventPhase: '" + phase + "'");
}
// 点击以后的结果
// Tag: 'DIV'. EventPhase: 'capture'
// Tag: 'P'. EventPhase: 'target'
// Tag: 'P'. EventPhase: 'target'
// Tag: 'DIV'. EventPhase: 'bubble'
1.2.3 事件的代理
因为事件会在冒泡阶段向上传播到父节点,因此可以将子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,这种方式称为事件的代理
var ul = document.querySelector('ul');
ul.addEventListener('click', function (event) {
if (event.target.tagName.toLowerCase() === 'li') {
// some code
}
});
上面代码中,click事件的监听函数定义在<ul>
节点,但是实际上,它处理的是子节点<li>
的click事件。这样做的好处是,只要定义一个监听函数,就能处理多个子节点的事件,而不用在每个<li>
节点上定义监听函数。而且以后再添加子节点,监听函数依然有效。
另外,我们可以使用stopPorpagation
方法来使事件传播到某个节点就停下来,不再传播
// stopPropagation不会停止在同一个element上的其他事件的执行
p.addEventListener('click', function (event) {
event.stopPropagation();
console.log(1);
});
p.addEventListener('click', function(event) {
// 会触发
console.log(2);
});
- 如果我们想不触发同一个element上的其他监听函数,可以使用
stopImmediatePropogation()
方法
1.3 事件对象
事件发生以后,会产生一个事件对象,作为参数传给监听函数。浏览器原生提供一个Event对象,所有事件都是这个对象的实例,即继承了Event.prototype
- Event构造函数:
event = new Event(type, option);
- type 一个字符串,表示事件的名称
- options 一个对象,表示事件对象的配置
- bubbles boolean
- default to false
- 表示对象是否冒泡
- cancelable boolean
- default to false
- 表示事情能否被取消,即能否用event.preventDefault()取消这个时间
- bubbles boolean
1.3.1 实例属性
- Event.bubbles
- boolean
- 表示当前事件是否会冒泡
- 只读属性,用于了解Event实例是否可以冒泡
- Event.eventPhase
- 返回当前事件所处的阶段,该属性只读
- 0 还没有发生
- 1 捕获阶段 处于从祖先节点向目标节点的传播过程当中
- 2 事件到达目标节点
- 3 事件处于冒泡阶段
- 返回当前事件所处的阶段,该属性只读
- Event.currentTarget
- 正在通过的节点
- Event.target
- 事件的原始触发节点
- Event.timeStamp
- Event.isTrusted
- 表示该事件是否由一个真实的用户行为产生
- Event.detail
- 只有浏览器的UI事件才具有
- 返回一个数值表示事件的某种信息
- 具体含义与事件类型相关
- 点击 次数
- 鼠标滚轮 距离
1.3.2 实例方法
- event.preventDefault()
- 取消浏览器对当前事件的默认行为
- 生效的前提是事件对象的cancelable属性为true
// HTML 代码为
// <input type="text" id="my-input" />
// 实现只接受小写的功能
var input = document.getElementById('my-input');
input.addEventListener('keypress', checkName, false);
function checkName(e) {
if (e.charCode < 97 || e.charCode > 122) {
e.preventDefault();
}
}
- event.stopPropagation()
- 阻止事件在DOM中继续传播,防止再触发定义在别的节点上的监听函数,但是不包括在当前节点上其他的事件监听函数
- event.stopImmediatePropogation()
- 阻止同一个事件的其他监听函数被调用
- 更彻底的阻止事件的传播
- event.composedPath()
- 返回一个数组
- 成员是事件的最底层节点和依次冒泡经过的所有上层节点
// HTML 代码如下
// <div>
// <p>Hello</p>
// </div>
var div = document.querySelector('div');
var p = document.querySelector('p');
div.addEventListener('click', function (e) {
console.log(e.composedPath());
}, false);
// [p, div, body, html, document, Window]
1.4 各类事件的描述
1.4.1 鼠标事件
- 继承MouseEvent接口
- click
- mouseDown + mouseUp
- dblclick 在用一个元素上双击鼠标时触发
- mouseDown + mouseUp + click
- mousedown 按下鼠标键时触发
- mouseup 释放按下的鼠标键的时候触发
- mousemove
- 当鼠标在一个结点内部移动的时候触发
- 当鼠标持续移动时,就会持续触发
- 应当对该事件的监听函数做一些限定,比如一定时间内只能运行一次
- mouseenter
- 进入一个节点时触发
- mouseover
- 鼠标进入一个节点时触发,进入子节点会再一次触发这个事件
- mouseout
- 鼠标离开一个节点的时候触发,离开父节点也会触发
- mouseleave
- 鼠标离开一个节点时触发,离开父节点不会触发这个事件
- contextmenu
- 按下鼠标右键时触发的
- wheel
- 滚动鼠标的滚轮时触发的,该事件继承的是WheelEvent接口
- click
- mouseEvent
- 浏览器提供一个MouseEvent构造函数,用于新建一个MouseEvent实例
var event = new MouseEvent(type, options);
- 第一个参数为字符串,表示事件名称
- 第二个参数是一个事件配置对象,可以配一些不同的属性
- screenX
- screenY
- clientX
- 相对于程序窗口的水平位置
- clientY
- 相对于程序窗口的垂直位置
- ctrlKey
- shiftKey
- altKey
- metaKey
- button
- 0 按下主键
- 1 按下辅助键
- 2 按下次要键
- buttons
1.4.2 键盘事件
键盘事件的种类
keydown
- 按下键盘的时候触发
keypress
- 按下有值的键再触发,即按下Ctrl, Alt, Shift, Meta这样的无值的键不会触发
- 对于有值的键,还是会先触发keydown事件,再触发这个事件
keyup
- 松开键盘的时候触发该事件
- 如果一直不松开按键,那么就会连续触发键盘事件
- 触发顺序:
- keydown
- keypress
- keydown
- keypress
- ….
- 放开 -> keyup
- 触发顺序:
KeyboardEvent 接口概述
- 描述用户与键盘的互动
- 继承了Event接口,并且定义了自己的实例属性和实例方法
- 浏览器原生提供KeyboardEvent构造函数,用来新建键盘事件的实例
new KeyboardEvent(type, options)
- 第一个参数为字符串,表示事件类型
- 第二个参数为一个事件配置对象,参数可选
- key
- code
- 0-9 digital0-digital9
- A-Z KeyA - KeyZ
- F1 - F12
- 方向键
- ArrowDown
- ArrowUp
- ArrowLeft
- ArrowRight
- Alt
- AltLeft/ AltRight
- similar to shift, ctrl
- location
- 返回键盘的区域
- ctrlKey
- shiftKey
- altKey
- metaKey
- repeat
- 看该案件是否被按着不放,以便判断是否重复这个键
KeyboardEvent实例方法
- getModifierState()
- 返回一个布尔值,表示是否按下或激活指定的功能键
- alt
- capslock
- control
- meta
- numlock
- shift
- 返回一个布尔值,表示是否按下或激活指定的功能键
- getModifierState()
1.4.3 进度事件
用来描述资源加载的进度,主要由:
- AJAX请求
<img>
<audio>
<video>
<style>
<link>
该类外部资源的加载触发,继承了ProgressEvent接口。主要包含以下几种事件:
- abort 外部资源中止加载时被触发
- error 由于错误导致外部资源无法加载时触发
- load 外部资源加载成功时触发
- loadstart 外部资源开始加载时触发
- loadend 外部资源停止加载时触发
- progress 外部资源加载过程中不断触发
- timeout 加载超时时触发
ProgressEvent接口
表单事件的种类
- input
- 当
<input>, <select>, <textarea>
的值发生变化时触发 - input事件会连续触发,每按下一个键,都会触发一次input事件的
- 当
- select
- 是在
<input> <select> <textarea>
里面的值发生变化的时候触发
- 是在
- change
- 在元素失去焦点时发生
- 即当有连续变化的时候,input事件会被触发很多次,而change事件只在失去焦点的时候被触发一次。
- 换个角度看,input事件是一定伴随着change事件的,具体分为以下几种情况
- 激活单选框或复选框时触发
- 用户提交时触发
- 当文本框或textarea元素的值发生改变,并且失去焦点的时候触发
- invalid
- 用户提交表单,当表单元素的值不满足校验条件,就会触发invalid事件
- reset
- 发生在表单对象上
- 表示表单重置时锁触发的事件
- submit
- 当表单数据向服务器提交时触发
- input
inputEvent接口
new InputEvent(type, options)
- type 字符串,表示事件名称
- options 配置对象
- inputType
- data 表示插入的字符串
- dataTransfer
1.4.5 触摸事件
触摸操作
- touch 一个触摸点
- 位置
- 大小
- 形状
- 压力
- 目标元素
- touchList 多个触摸点的集合
- 成员为Touch的实例对象
- 属性
- length 表示触摸点的数量
- item() 返回指定的成员
- touchEvent 触摸引发的事件实例
- touch 一个触摸点
Touch 接口概述
var touch = new Touch(touchOptions)
- touchOptions
- identifier
- 触摸点的唯一ID
- target
- clientX
- clientY
- screenX
- screenY
- pageX
- pageY
- radiusX
- radiusY
- rotationAngle
- force
- 0 -1 范围
- 表示触摸压力
- identifier
触摸事件的种类
拖拉定义
- 用户在某个对象上按下鼠标键不放,拖动它到另一个位置,然后释放鼠标键,将该对象放在那里
拖拉的对象
- 元素节点
- 图片
- 链接
- 选中的文字
1.4.7 其他常见事件
- 资源事件
- beforeunload
- 在窗口,文档,各种资源将要卸载前触发
- 用于防止用户不小心卸载资源
- unload
- 在窗口关闭或者document对象将要卸载时触发
- 触发顺序排在beforeunload, pagehide事件后面
- load
- 在页面或者某个资源加载成功时触发
- 页面或者资源从浏览器缓存加载,并不会触发load事件
- beforeunload
- session历史事件
- pageshow
- 页面加载时触发,如果要指定页面每次加载时都运行的打字吗,可以放在这个事件的监听函数当中
- pagehide
- popstate
- 在浏览器的history对象的当前记录发生显式切换时触发
- hashchange
- URL的hash部分发生变化的时候触发
- pageshow
- 网页状态事件
- DOMContentLoaded 事件
- 网页下载并解析完成以后在document对象上触发该事件
- DOMContentLoaded 事件
- 窗口事件
- scroll
- 用户拖动滚动条
- resize
- fullscreenchange
- fullscreenerror
- scroll
- 焦点事件
- focus 获得焦点以后触发
- blur 失去焦点以后触发
- focusin 将要获得焦点时触发
- focusout 将要失去焦点时触发
2. 浏览器模型
主要来介绍浏览器提供的各种JS接口
2.1 浏览器环境概述
- 代码嵌入网页方法