11本文是 ** 重温基础** 系列文章的第二十篇。
2+
3+ 这是第三个基础系列的第一篇,欢迎持续关注呀!
4+ ** 重温基础** 系列的【初级】和【中级】的文章,已经统一整理到我的【[ Cute-JavaScript] ( http://js.pingan8787.com ) 】的JavaScript基础系列中。
25今日感受:电影有时候看的是缘分。
36
4- ** 本章节复习的是JS中的事件,事件冒泡捕获代理等等 。**
7+ ** 本章节复习的是JS中的事件,事件冒泡捕获代理模拟等等 。**
58
69** 前置知识:**
710JavaScript与HTML的交互式通过** 事件** 来实现的,是文档或浏览器窗口中发生的一些特定的交互瞬间。
@@ -230,7 +233,7 @@ var my_event = {
230233当触发一个DOM上的事件时,都会产生一个事件对象` event ` ,并作为参数传入事件处理程序,这个对象包含所有与事件相关的信息。包括导致事件的元素、事件类型等其他信息。
231234
232235### 3.1 DOM中的事件对象
233- 无论指定事件处理程序时使用am方法 (DOM0级方法或DOM2级方法),都会传入` event ` 对象:
236+ 无论指定事件处理程序时使用什么方法 (DOM0级方法或DOM2级方法),都会传入` event ` 对象:
234237``` js
235238var leo = document .getElementById (' leo' );
236239leo .onclick = function (event ){
@@ -245,18 +248,319 @@ leo.addEventListener('click',function(event){
245248
246249![ event成员2] ( http://images.pingan8787.com/20190127%E4%BA%8B%E4%BB%B6%E5%AF%B9%E8%B1%A1%E6%88%90%E5%91%982.png )
247250
251+ 我们可以使用` event ` 中的对象和方法:
252+ * 阻止事件的默认行为
253+ ``` js
254+ var leo = document .getElementById (' leo' );
255+ leo .onclick = function (event ){
256+ // 只有当 event 中的 cancelable 属性为true的事件
257+ event .preventDefault ();
258+ }
259+ ```
260+ * 立即停止事件在DOM的传播
261+
262+ 通过调用` event.stopPropagation() ` 方法避免弹框出现两次。
263+ ``` js
264+ var leo = document .getElementById (' leo' );
265+ leo .onclick = function (event ){
266+ alert (' leo' );
267+ event .stopPropagation ();
268+ }
269+ document .body .onclick = function (event ){
270+ alert (' hello leo' );
271+ }
272+ ```
273+
274+ ### 3.2 IE中的事件对象
275+ 访问IE中的事件对象` event ` ,方法有多种,取决于事件处理程序的方法:
276+ * DOM0级方法,使用` window.event `
277+
278+ ``` js
279+ var leo = document .getElementById (' leo' );
280+ leo .onclick = function (){
281+ var event = window .event ;
282+ alert (event .type ); // 'click'
283+ }
284+ ```
285+
286+ * IE的` attachEvent ` 方法,` event ` 作为参数传入(也可以使用` window.event ` )
287+
288+ ``` js
289+ var leo = document .getElementById (' leo' );
290+ leo .attachEvent (' onclick' ,function (event ){
291+ alert (event .type ); // 'click'
292+ },false );
293+ ```
294+
295+ ### 3.3 跨浏览器的事件对象
296+ 虽然DOM和IE中` event ` 对象不同,但我们也可以和前面的 ** 跨浏览器事件处理程序** 处理一样,通过他们之间的区别,实现映射:
297+ ``` js
298+ var my_event = {
299+ myAddFun : function (element , type , handler ){
300+ // do some thing
301+ },
302+ // 返回对event的引用
303+ getMyEvent : function (event ){
304+ return event ? event : window .event ;
305+ },
306+ // 返回事件的目标
307+ getMyTarget : function (event ){
308+ return event .target || event .srcElement ;
309+ },
310+ // 取消事件的默认行为
311+ preventDefault : function (event ){
312+ if (event .preventDefault ){
313+ event .preventDefault ();
314+ }else {
315+ event .returnValue = false ;
316+ }
317+ },
318+
319+ myRemoveFun : function (element , type , handler ){
320+ // do some thing
321+ },
322+
323+ // 阻止事件流
324+ stopPropagetion : function (event ){
325+ if (event .stopPropagetion ){
326+ event .stopPropagetion ();
327+ }else {
328+ event .cancelBubble = true ;
329+ }
330+ }
331+ }
332+
333+ var leo = document .getElementById (' leo' );
334+ leo .onclick = function (event ){
335+ alert (' leo' );
336+ event = my_event (event );
337+ my_event .stopPropagation (event );
338+ }
339+
340+ leo .onclick = function (event ){
341+ alert (' hello world' );
342+ }
343+ ```
248344
249345## 4.事件类型
346+ Web浏览器中的事件类型有很多,** DOM3级事件** 规定有以下几类事件类型:
347+ * ** UI事件** :当用户与页面上元素交互时触发;
348+ * ** 焦点事件** :当元素失去或获取焦点时触发;
349+ * ** 鼠标事件** :当用户通过鼠标在页面操作时触发;
350+ * ** 滚轮事件** :当使用鼠标滚轮(或类似设备)时触发;
351+ * ** 文本事件** :当在文档中输入文本时触发;
352+ * ** 键盘事件** :当用户通过键盘操作时触发;
353+ * ** 合成事件** :当为IME输入字符时触发;
354+ * ** 变动事件** :当底层DOM结构变动时触发;
355+
356+ 具体每个方法的详细介绍,可以查看** [ W3school HTML DOM Event 对象] ( http://www.w3school.com.cn/jsref/dom_obj_event.asp ) **
357+ 或者查看《JavaScript高级程序设计(第三版)》的第362页开始。
358+ 我后面会单独整理一篇,介绍这些事件的文章。
359+
250360
251361## 5.事件委托
362+ 简单理解就是讲一个响应事件委托到另一个元素。
363+ ** 事件委托** 利用事件冒泡,指定一个事件处理程序来管理某一类型的所有事件,比如我们通过一个函数来代替其他三个函数:
364+ ``` html
365+ <ul id =" btn" >
366+ <li id =" btn1" >按钮1</li >
367+ <li id =" btn2" >按钮2</li >
368+ <li id =" btn3" >按钮3</li >
369+ </ul >
370+ ```
371+ ``` js
372+ var btn1 = document .getElementById (' btn1' );
373+ var btn2 = document .getElementById (' btn2' );
374+ var btn3 = document .getElementById (' btn3' );
375+ // my_event 在前面定义了
376+ my_event .myAddFun (btn1, ' click' , function (event ){
377+ alert (' btn1点击' );
378+ });
379+ my_event .myAddFun (btn2, ' click' , function (event ){
380+ alert (' btn2点击' );
381+ });
382+ my_event .myAddFun (btn3, ' click' , function (event ){
383+ alert (' btn3点击' );
384+ });
385+ ```
386+ 下面我们在** DOM树层级更高的元素上添加一个事件处理函数** ,来做事件委托,我们这么重写这段代码:
387+ ``` js
388+ var btn = document .getElementById (' btn' );
389+ my_event .myAddFun (btn, ' click' , function (event ){
390+ event = my_event .getMyEvent (event );
391+ var target = my_event .getMyTarget (event );
392+ switch (target .id ){
393+ case " btn1" :
394+ alert (' btn1点击' );
395+ break ;
396+ case " btn2" :
397+ alert (' btn2点击' );
398+ break ;
399+ case " btn3" :
400+ alert (' btn3点击' );
401+ break ;
402+ }
403+ });
404+ ```
405+ 最适合采用事件委托技术的事件包括:` click ` /` mousedown ` /` mouseup ` /` keyup ` /` keydown ` /` keypress ` ,虽然` mouseover ` 和` mouseout ` 事件也有冒泡,但因为不好处理它们并且经常需要重新计算元素位置。
406+
407+ 可以看出,** 事件委托** 有以下优点:
408+ * 减少内存消耗
409+ * 动态绑定事件
252410
253411## 6.事件模拟
412+ JavaScript的事件模拟主要用来在任意时刻触发特定事件。
413+
414+ ### 6.1 DOM中的事件模拟
415+ 在` document ` 对象上使用` createEvent() ` 方法创建一个` event ` 对象。
416+ ` createEvent() ` 接收一个参数,即要创建的事件类型的字符串。
417+ DOM2级中,所有这些字符串都使用英文复数形式,DOM3级中都变成单数,也可以是下面中的字符串:
418+ * UIEvents : 一般化的UI事件(鼠标和键盘事件都继承自UI事件)(DOM3级中` UIEvent ` )
419+ * MouseEvents : 一般化的鼠标事件(DOM3级中` MouseEvent ` )
420+ * MutationEvents : 一般化的DOM滚动事件(DOM3级中` MutationEvent ` )
421+ * HTMLEvents : 一般化的HTML事件(DOM3级中` HTMLEvent ` )
422+
423+ 创建` event ` 之后,我们需要使用` dispatchEvent() ` 方法去触发这个事件,需要传入一个参数,参数是需要触发事件的event对象。
424+
425+ 所有支持事件的DOM节点都支持这个方法。事件触发之后,事件就能照样冒泡并引发响应事件处理程序的执行。
426+
427+ #### 6.1.1 模拟鼠标事件
428+ 使用` createEvent() ` 方法传入` MouseEvents ` 创建一个鼠标事件,返回的对象有一个` initMouseEvent() ` 方法,用于指定与该鼠标事件相关的信息,有15个参数:
429+ * type : 字符串,表示触发的事件类型,如` click `
430+ * bubble : 布尔值,表示是否冒泡,为了精确模拟鼠标事件,通常设置为true
431+ * cancelable :布尔值,表示是否可以取消,为了精确模拟鼠标事件,通常设置为true
432+ * view : 与事件关联的视图,基本都设置为` document.defaultView `
433+ * detail : 整数,与事件有关的详细信息,基本设置为0
434+ * screenX : 整数,事件相对屏幕的X坐标
435+ * screenY : 整数,事件相对屏幕的Y坐标
436+ * clientX : 整数,事件相对视口的X坐标
437+ * clientY : 整数,事件相对视口的Y坐标
438+ * ctrlKey : 布尔值,表示是否按下Ctrl键,默认false
439+ * altKey : 布尔值,表示是否按下Alt键,默认false
440+ * shiftKey : 布尔值,表示是否按下Shift键,默认false
441+ * metaKey : 布尔值,表示是否按下Meta键,默认false
442+ * button : 整数,表示按下哪个鼠标键,默认0
443+ * relatedTarget : 对象,表示与事件相关的对象,只在` mouseover ` 和` mouseout ` 时使用
444+
445+ 案例:
446+ ``` js
447+ var btn = document .getElementById (' btn' );
448+ var myEvent = document .createEvent (' MouseEvents' );
449+ myEvent .initMouseEvent (
450+ ' click' , true , true , document .defaultView ,
451+ 0 , 0 , 0 , 0 , 0 ,
452+ false , false , false , false , 0 , null
453+ )
454+ btn .dispatchEvent (myEvent);
455+ ```
456+
457+ #### 6.1.2 模拟键盘事件
458+ DOM3级规定,使用` createEvent() ` 方法传入` KeyboardEvent ` 创建一个键盘事件,返回的对象有一个` initKeyEvent() ` 方法,有8个参数:
459+ * type : 字符串,表示触发的事件类型,如` keydown `
460+ * bubble : 布尔值,表示是否冒泡,为了精确模拟键盘事件,通常设置为true
461+ * cancelable :布尔值,表示是否可以取消,为了精确模拟键盘事件,通常设置为true
462+ * view : 与事件关联的视图,基本都设置为` document.defaultView `
463+ * key : 整数,表示按下的键的键码
464+ * localtion : 整数,表示按下哪里的键,默认0表示主键盘,1表示左,2表示右,3表示数字键盘,4表示移动设备(即虚拟键盘),5表示手柄
465+ * modifiers : 字符串,空格分隔的修改件列表,如"shift"
466+ * repeat : 整数,在一行中按了多少次这个键
467+ 由于DOM3级不提倡使用` keypress ` 事件,因此只能用这个方式来模拟` keyup ` /` keydown ` 事件。
468+
469+ 模拟按住Shift和A键的案例:
470+ ``` js
471+ var btn = document .getElementById (' btn' );
472+ var myEvent;
473+
474+ // 以DOM3级方式创建
475+ if (document .implementation .hasFeature (' KeyboardEvents' , ' 3.0' )){
476+ myEvent = document .createEvent (' KeyboardEvent' );
477+ myEvent .initKeyboardEvent (
478+ ' keydown' , true , true , document .defaultView ,
479+ ' a' , 0 , ' Shift' , 0
480+ );
481+ }
482+ btn .dispatchEvent (myEvent);
483+ ```
484+
485+ #### 6.1.3 模拟其他事件
486+ 如模拟** 变动事件** 和** HTML事件** 。
254487
488+ * 模拟** 变动事件**
255489
256- ## 参考文章:
257- 1 . [ MDN 闭包] ( https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures#%E8%AF%8D%E6%B3%95%E4%BD%9C%E7%94%A8%E5%9F%9F )
258- 2 . 《JavaScript高级程序设计》第13章 事件
490+ 通过` createEvent() ` 传入` MutationEvents ` 参数创建,返回一个` initMutationEvent() ` 方法,这个方法接收参数包括:` type ` /` bubbles ` /` cancelable ` /` relatedNode ` /` preValue ` /` newValue ` /` attrName ` /` attrChange ` ,下面模拟一个案例:
491+ ``` js
492+ var btn = document .getElementById (' btn' );
493+ var myEvent = document .createEvent (' MutationEvents' );
494+ myEvent .initMutationEvent (
495+ ' DOMNodeInserted' , true , false , someNode, ' ' , ' ' , ' ' , 0
496+ );
497+ btn .dispatchEvent (myEvent);
498+ ```
499+
500+ * 模拟** HTML事件**
501+
502+ 通过` createEvent() ` 传入` HTMLEvents ` 参数创建,返回一个` initEvent() ` 方法,下面模拟一个案例:
503+ ``` js
504+ var btn = document .getElementById (' btn' );
505+ var myEvent = document .createEvent (' HTMLEvents' );
506+ myEvent .initEvent (' focus' , true , false );
507+ btn .dispatchEvent (myEvent);
508+ ```
509+
510+ #### 6.1.4 自定义DOM事件
511+ 通过` createEvent() ` 传入` CustomEvent ` 参数创建,返回一个` initCustomEvent() ` 方法,有4个参数:
512+ * type : 字符串,表示触发的事件类型,如` keydown `
513+ * bubble : 布尔值,表示是否冒泡,为了精确模拟键盘事件,通常设置为true
514+ * cancelable :布尔值,表示是否可以取消,为了精确模拟键盘事件,通常设置为true
515+ * detail : 对象,任意值,保存在` event ` 对象的` detail ` 属性中
516+
517+ 案例:
518+ ``` js
519+ var btn = document .getElementById (' btn' );
520+ var myEvent;
521+
522+ // my_event在前面定义 2.6 跨浏览器事件处理程序
523+ my_event .addMyEvent (btn, ' myevent' , function (event ){
524+ alert (' btn detail ' , event .detail );
525+ });
526+
527+ my_event .addMyEvent (document , ' myevent' , function (event ){
528+ alert (' document detail ' , event .detail );
529+ });
530+
531+
532+ // 以DOM3级方式穿件
533+ if (document .implementation .hasFeature (' CustomEvents' , ' 3.0' )){
534+ myEvent = document .createEvent (' CustomEvent' );
535+ myEvent .initCustomEvent (
536+ ' myevent' , true , false , ' hello leo' ,
537+ );
538+ btn .dispatchEvent (myEvent);
539+ }
540+ ```
541+
542+ ### 6.2 IE中的事件模拟
543+ IE8及之前的版本模拟事件和DOM中模拟思路相似:想创建` event对象 ` 再指定信息,最后触发。
544+ 区别在于,IE中使用` document.createEventObject() ` 方法创建` event对象 ` ,并且不接收参数,返回一个通用` event对象 ` ,我们要做的就是给这个` event对象 ` 添加信息,最后在目标上调用` fireEvent() ` 方法,并接受两个参数(事件处理程序的名称和` event对象 ` )。
545+ 在调用` fireEvent() ` 方法会自动添加` srcElement ` 和` type ` 属性,我们需要手动添加其他属性,下面模拟一个click事件:
546+ ``` js
547+ var btn = document .getElementById (' btn' );
548+ var myEvent = document .createEventObject ();
549+
550+ myEvent .screenX = 100 ;
551+ myEvent .screenY = 0 ;
552+ myEvent .clientX = 100 ;
553+ myEvent .clientY = 0 ;
554+ myEvent .ctrlKey = false ;
555+ myEvent .altKey = false ;
556+ myEvent .shiftKey = false ;
557+ myEvent .button = 0 ;
558+
559+ btn .fireEvent (' onclick' , event );
560+ ```
259561
562+ ## 参考文章
563+ 1 . 《JavaScript高级程序设计》第13章 事件
260564
261565** 本部分内容到这结束**
262566
0 commit comments