Skip to content

Commit 0dffa5d

Browse files
committed
docs(events): add Event
1 parent e7ab673 commit 0dffa5d

2 files changed

Lines changed: 287 additions & 0 deletions

File tree

chapters.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
- events/: 事件
5858
- events/eventtarget.md: EventTarget 接口
5959
- events/model.md: 事件模型
60+
- events/Event.md: Event 对象
6061
- events/globaleventhandlers.md: GlobalEventHandlers 接口
6162
- bom/: 浏览器模型
6263
- bom/cookie.md: Cookie

docs/events/event.md

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
# Event 对象
2+
3+
## 概述
4+
5+
事件发生以后,会产生一个事件对象,作为参数传给监听函数。浏览器原生提供一个`Event`对象,所有的事件都是这个对象的实例,或者说继承了`Event.prototype`对象。
6+
7+
`Event`对象本身就是一个构造函数,可以用来生成新的实例。
8+
9+
```javascript
10+
event = new Event(type, options);
11+
```
12+
13+
`Event`构造函数接受两个参数。第一个参数`type`是字符串,表示事件的名称;第二个参数`options`是一个对象,表示事件对象的配置。该对象主要有下面两个属性。
14+
15+
- `bubbles`:布尔值,可选,默认为`false`,表示事件对象是否冒泡。
16+
- `cancelable`:布尔值,可选,默认为`false`,表示事件是否可以被取消,即能否用`Event.preventDefault()`取消这个事件。一旦事件被取消,就好像从来没有发生过,不会触发浏览器对该事件的默认行为。
17+
18+
```javascript
19+
var ev = new Event(
20+
'look',
21+
{
22+
'bubbles': true,
23+
'cancelable': false
24+
}
25+
);
26+
document.dispatchEvent(ev);
27+
```
28+
29+
上面代码新建一个`look`事件实例,然后使用`dispatchEvent`方法触发该事件。
30+
31+
注意,如果不是显式指定`bubbles`属性为`true`,生成的事件就只能在“捕获阶段”触发监听函数。
32+
33+
```javascript
34+
// HTML 代码为
35+
// <div><p>Hello</p></div>
36+
var div = document.querySelector('div');
37+
var p = document.querySelector('p');
38+
39+
function callback(event) {
40+
var tag = event.currentTarget.tagName;
41+
console.log('Tag: ' + tag); // 没有任何输出
42+
}
43+
44+
div.addEventListener('click', callback, false);
45+
46+
var click = new Event('click');
47+
p.dispatchEvent(click);
48+
```
49+
50+
上面代码中,`p`元素发出一个`click`事件,该事件默认不会冒泡。`div.addEventListener`方法指定在冒泡阶段监听,因此监听函数不会触发。如果写成`div.addEventListener('click', callback, true)`,那么在“捕获阶段”可以监听到这个事件。
51+
52+
另一方面,如果这个事件在`div`元素上触发。
53+
54+
```javascript
55+
div.dispatchEvent(click);
56+
```
57+
58+
那么,不管`div`元素是在冒泡阶段监听,还是在捕获阶段监听,都会触发监听函数。因为这时`div`元素是事件的目标,不存在是否冒泡的问题,`div`元素总是会接收到事件,因此导致监听函数生效。
59+
60+
## 实例属性
61+
62+
### Event.bubbles,Event.eventPhase
63+
64+
`Event.bubbles`属性返回一个布尔值,表示当前事件是否会冒泡。该属性为只读属性,一般用来了解 Event 实例是否可以冒泡。前面说过,除非显式声明,`Event`构造函数生成的事件,默认是不冒泡的。
65+
66+
`Event.eventPhase`属性返回一个整数常量,表示事件目前所处的阶段。该属性只读。
67+
68+
```javascript
69+
var phase = event.eventPhase;
70+
```
71+
72+
`Event.eventPhase`的返回值有四种可能。
73+
74+
- 0,事件目前没有发生。
75+
- 1,事件目前处于捕获阶段,即处于从祖先节点向目标节点的传播过程中。
76+
- 2,事件到达目标节点,即`Event.target`属性指向的那个节点。
77+
- 3,事件处于冒泡阶段,即处于从目标节点向祖先节点的反向传播过程中。
78+
79+
### Event.cancelable,Event.cancelBubble,event.defaultPrevented
80+
81+
`Event.cancelable`属性返回一个布尔值,表示事件是否可以取消。该属性为只读属性,一般用来了解 Event 实例的特性。
82+
83+
大多数浏览器的原生事件是可以取消的。比如,取消`click`事件,点击链接将无效。但是除非显式声明,`Event`构造函数生成的事件,默认是不可以取消的。
84+
85+
```javascript
86+
var evt = new Event('foo');
87+
evt.cancelable // false
88+
```
89+
90+
`Event.cancelable`属性为`true`时,调用`Event.preventDefault()`就可以取消这个事件,阻止浏览器对该事件的默认行为。
91+
92+
如果事件不能取消,调用`Event.preventDefault()`会没有任何效果。所以使用这个方法之前,最好用`Event.cancelable`属性判断一下是否可以取消。
93+
94+
```javascript
95+
function preventEvent(event) {
96+
if (event.cancelable) {
97+
event.preventDefault();
98+
} else {
99+
console.warn('This event couldn\'t be canceled.');
100+
console.dir(event);
101+
}
102+
}
103+
```
104+
105+
`Event.cancelBubble`属性是一个布尔值,如果设为`true`,相当于执行`Event.stopPropagation()`,可以阻止事件的传播。
106+
107+
`Event.defaultPrevented`属性返回一个布尔值,表示该事件是否调用过`Event.preventDefault`方法。该属性只读。
108+
109+
```javascript
110+
if (event.defaultPrevented) {
111+
console.log('该事件已经取消了');
112+
}
113+
```
114+
115+
### Event.currentTarget,Event.target
116+
117+
`Event.currentTarget`属性返回事件当前所在的节点,即正在执行的监听函数所绑定的那个节点。
118+
119+
`Event.target`属性返回原始触发事件的那个节点,即事件最初发生的节点。事件传播过程中,不同节点的监听函数内部的`Event.target``Event.currentTarget`属性的值是不一样的,前者总是不变的,后者则是指向监听函数所在的那个节点对象。
120+
121+
```javascript
122+
// HTML代码为
123+
// <p id="para">Hello <em>World</em></p>
124+
function hide(e) {
125+
console.log(this === e.currentTarget); // 总是 true
126+
console.log(this === e.target); // 有可能不是 true
127+
e.target.style.visibility = 'hidden';
128+
}
129+
130+
para.addEventListener('click', hide, false);
131+
```
132+
133+
上面代码中,如果在`para`节点的`<em>`子节点上面点击,则`e.target`指向`<em>`子节点,导致`<em>`子节点(即 World 部分)会不可见。如果点击 Hello 部分,则整个`para`都将不可见。
134+
135+
### Event.type
136+
137+
`Event.type`属性返回一个字符串,表示事件类型。事件的类型是在生成事件的时候。该属性只读。
138+
139+
```javascript
140+
var evt = new Event('foo');
141+
evt.type // "foo"
142+
```
143+
144+
### Event.timeStamp
145+
146+
`Event.timeStamp`属性返回一个毫秒时间戳,表示事件发生的时间。它是相对于网页加载成功开始计算的。
147+
148+
```javascript
149+
var evt = new Event('foo');
150+
evt.timeStamp // 3683.6999999995896
151+
```
152+
153+
它的返回值有可能是整数,也有可能是小数(高精度时间戳),取决于浏览器的设置。
154+
155+
下面是一个计算鼠标移动速度的例子,显示每秒移动的像素数量。
156+
157+
```javascript
158+
var previousX;
159+
var previousY;
160+
var previousT;
161+
162+
window.addEventListener('mousemove', function(event) {
163+
if (
164+
previousX !== undefined &&
165+
previousY !== undefined &&
166+
previousT !== undefined
167+
) {
168+
var deltaX = event.screenX - previousX;
169+
var deltaY = event.screenY - previousY;
170+
var deltaD = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
171+
172+
var deltaT = event.timeStamp - previousT;
173+
console.log(deltaD / deltaT * 1000);
174+
}
175+
176+
previousX = event.screenX;
177+
previousY = event.screenY;
178+
previousT = event.timeStamp;
179+
});
180+
```
181+
182+
### Event.isTrusted
183+
184+
`Event.isTrusted`属性返回一个布尔值,表示该事件是否由真实的用户行为产生。比如,用户点击链接会产生一个`click`事件,该事件是用户产生的;`Event`构造函数生成的事件,则是脚本产生的。
185+
186+
```javascript
187+
var evt = new Event('foo');
188+
evt.isTrusted // false
189+
```
190+
191+
上面代码中,`evt`对象是脚本产生的,所以`isTrusted`属性返回`false`
192+
193+
## 实例方法
194+
195+
### Event.preventDefault()
196+
197+
`Event.preventDefault`方法取消浏览器对当前事件的默认行为。比如点击链接后,浏览器默认会跳转到另一个页面,使用这个方法以后,就不会跳转了;再比如,按一下空格键,页面向下滚动一段距离,使用这个方法以后也不会滚动了。该方法生效的前提是,事件对象的`cancelable`属性为`true`,如果为`false`,调用该方法没有任何效果。
198+
199+
注意,该方法只是取消事件对当前元素的默认影响,不会阻止事件的传播。如果要阻止传播,可以使用`stopPropagation()``stopImmediatePropagation()`方法。
200+
201+
```javascript
202+
// HTML 代码为
203+
// <input type="checkbox" id="my-checkbox" />
204+
var cb = document.getElementById('my-checkbox');
205+
206+
cb.addEventListener(
207+
'click',
208+
function (e){ e.preventDefault(); },
209+
false
210+
);
211+
```
212+
213+
上面代码中,浏览器的默认行为是单击会选中单选框,取消这个行为,就导致无法选中单选框。
214+
215+
利用这个方法,可以为文本输入框设置校验条件。如果用户的输入不符合条件,就无法将字符输入文本框。
216+
217+
```javascript
218+
// HTML 代码为
219+
// <input type="text" id="my-input" />
220+
var input = document.getElementById('my-input');
221+
input.addEventListener('keypress', checkName, false);
222+
223+
function checkName(e) {
224+
if (e.charCode < 97 || e.charCode > 122) {
225+
e.preventDefault();
226+
}
227+
}
228+
```
229+
230+
上面代码为文本框的`keypress`事件设定监听函数后,将只能输入小写字母,否则输入事件的默认行为(写入文本框)将被取消,导致不能向文本框输入内容。
231+
232+
### Event.stopPropagation()
233+
234+
`stopPropagation`方法阻止事件在 DOM 中继续传播,防止再触发定义在别的节点上的监听函数,但是不包括在当前节点上其他的事件监听函数。
235+
236+
```javascript
237+
function stopEvent(e) {
238+
e.stopPropagation();
239+
}
240+
241+
el.addEventListener('click', stopEvent, false);
242+
```
243+
244+
上面代码中,`click`事件将不会进一步冒泡到`el`节点的父节点。
245+
246+
### Event.stopImmediatePropagation()
247+
248+
`Event.stopImmediatePropagation`方法阻止同一个事件的其他监听函数被调用,不管监听函数定义在当前节点还是其他节点。也就是说,该方法阻止事件的传播,比`Event.stopPropagation()`更彻底。
249+
250+
如果同一个节点对于同一个事件指定了多个监听函数,这些函数会根据添加的顺序依次调用。只要其中有一个监听函数调用了`Event.stopImmediatePropagation`方法,其他的监听函数就不会再执行了。
251+
252+
```javascript
253+
function l1(e){
254+
e.stopImmediatePropagation();
255+
}
256+
257+
function l2(e){
258+
console.log('hello world');
259+
}
260+
261+
el.addEventListener('click', l1, false);
262+
el.addEventListener('click', l2, false);
263+
```
264+
265+
上面代码在`el`节点上,为`click`事件添加了两个监听函数`l1``l2`。由于`l1`调用了`event.stopImmediatePropagation`方法,所以`l2`不会被调用。
266+
267+
### Event.composedPath()
268+
269+
`Event.composedPath()`返回一个数组,成员是事件的最底层节点和依次冒泡经过的所有上层节点。
270+
271+
```javascript
272+
// HTML 代码如下
273+
// <div>
274+
// <p>Hello</p>
275+
// </div>
276+
var div = document.querySelector('div');
277+
var p = document.querySelector('p');
278+
279+
div.addEventListener('click', function (e) {
280+
console.log(e.composedPath());
281+
}, false);
282+
// [p, div, body, html, document, Window]
283+
```
284+
285+
上面代码中,`click`事件的最底层节点是`p`,向上依次是`div``body``html``document``Window`
286+

0 commit comments

Comments
 (0)