js中关于DOM的操作很多,因此js事件机制也就尤为重要。

事件绑定形式:

一. 内联形式

耦合度高,不利于维护

<button onclick="alert('你点击了这个按钮');">点击这个按钮</button>

二. 属性绑定(DOM0级事件)

只能绑定一个函数

button.onclick = function() {};

三. 事件监听函数(DOM2级事件)

element.addEventListener(<event-name>, <callback>, <use-capture>);

element.removeEventListener(<event-name>, <callback>, <use-capture>);

element.attachEvent(event, callback)(IE11以后用addEventLisener);

element.detachEvent(event, callback)(IE11以后用addEventLisener);

事件代理

在父元素上绑定事件,监听子元素的事件。主要用于子元素是新建元素或者子元素个数很多的情况下。这种方法可以提高性能,同时避免提前绑定元素事件而导致新建元素的事件没有生效的结果。

<ul> <li>11111111111111111111</li> </ul>

  1. document.addEventListener('click', function (e) {
  2. console.log('document currentTarget: ' + e.currentTarget.nodeName);
  3. console.log('document target: ' + e.target.nodeName);
  4. if (e.target.nodeName === 'LI') {
  5. console.log('dom delegate: ' + e.eventPhase);
  6. }
  7.  
  8. console.log(this);
  9. }, true);

事件触发顺序

  • Event Capturing(事件捕获): Netscape
  • Event Bubbling(事件冒泡): IE

这两种方式确定了事件执行的前后顺序,只不过后来W3C对DOM2的事件模型给出了一个规范:首先进入事件捕获阶段->达到元素后->进入事件冒泡阶段。

可以通过event.eventPhase查看事件触发阶段:

eventPhase (number): 这个属性的数字表示当前事件触发在什么阶段。

  • 0: none
  • 1: 捕获
  • 2: 目标
  • 3: 冒泡

1. DOM0

在元素处于目标时触发该事件。

2. DOM2
当addEventListener的最后参数为false时,是在冒泡阶段触发。如果是true的话是在捕获阶段出发。attachEvent始终是冒泡阶段触发。

允许捕获机制的事件流触发顺序:

事件流的触发顺序是首先从document元素开始,触发绑定在document上的捕获事件,依次向下,直到目标元素上。然后触发绑定在目标元素上的事件。最后依次向上,直到触发document元素上绑定的捕获事件。分别可以对于捕获阶段,处于目标阶段,冒泡阶段,捕获过程和冒泡过程并不包含目标元素阶段。

尝试下面的函数:

  1. <ul>
  2. <li>11111111111111111111</li>
  3. </ul>
  4. <script>
  5. document.querySelector('li').addEventListener('click', function (e) {
  6. console.log('False currentTarget: ' + e.currentTarget.nodeName);
  7. console.log('False target: ' + e.target.nodeName);
  8. console.log(e.eventPhase);
  9. console.log(this);
  10. }, false);
  11. document.querySelector('li').addEventListener('click', function (e) {
  12. console.log('True currentTarget: ' + e.currentTarget.nodeName);
  13. console.log('True target: ' + e.target.nodeName);
  14. console.log(e.eventPhase);
  15. console.log(this);
  16. }, true);
  17.  
  18. document.querySelector('ul').addEventListener('click', function (e) {
  19. console.log('ul false currentTarget: ' + e.currentTarget.nodeName);
  20. console.log('ul false target: ' + e.target.nodeName);
  21. console.log(e.eventPhase);
  22. console.log(this);
  23. }, false);
  24. document.querySelector('ul').addEventListener('click', function (e) {
  25. console.log('ul true currentTarget: ' + e.currentTarget.nodeName);
  26. console.log('ul true target: ' + e.target.nodeName);
  27. console.log(e.eventPhase);
  28. console.log(this);
  29. }, true);
  30. document.querySelector('li').onclick = function (e) {
  31. console.log('Onclick currentTarget: ' + e.currentTarget.nodeName);
  32. console.log('Onclick target: ' + e.target.nodeName);
  33. console.log(e.eventPhase);
  34. console.log(this);
  35. };
  36.  
  37. </script>

BeCareful: 可以看到,当点击li的时候,前两个绑定的事件是按照顺序来执行的,并没有先执行捕获事件然后执行冒泡事件,而是按照绑定顺序执行的。且event.eventPhase的值为2。

原因是:浏览器针对于事件的触发机制是,执行每个阶段会先设置在哪个阶段,然后在node的事件数组里执行相应阶段的事件。如果处于目标阶段是不区分捕获或者冒泡阶段的,直接按照注册顺序执行当前事件数组里的函数。event.eventPhase是在调用这些方法的时候设置的。而true和false是在注册的时候开发者传入的。

注释里面的那段话的意思就是,在目标阶段会触发捕获和冒泡事件的监听函数,因此,它会按照注册顺序执行,跟我们平时理解的顺序并不一样。

自定义事件

DOM3级还定义了自定义事件,自定义事件不是由DOM原生触发的,它的目的是让开发人员创建自己的事件。要创建的自定义事件可以由createEvent("CustomEvent");
返回的对象有一个initCustomEvent()方法接收如下四个参数。

1)type:字符串,触发的事件类型,自定义。例如 “keyDown”,“selectedChange”;

2)bubble(布尔值):标示事件是否应该冒泡;

3)cancelable(布尔值):标示事件是否可以取消;

4)detail(对象):任意值,保存在event对象的detail属性中;

可以像分配其他事件一样在DOM中分派创建的自定义事件对象。如:

  1. var div = document.getElementById("myDiv");
  2. EventUtil.addEventHandler(div,"myEvent", function () {
  3. alert("div myEvent!");
  4. });
  5. EventUtil.addEventHandler(document,"myEvent",function(){
  6. alert("document myEvent!");
  7. });
  8. if(document.implementation.hasFeature("CustomEvents","3.0")){
  9. var e = document.createEvent("CustomEvent");
  10. e.initCustomEvent("myEvent",true,false,"hello world!");
  11. div.dispatchEvent(e);
  12. }

事件对象及行为

1. 事件目标

  1. event = event || window.event;
  2. target = event.target || event.srcElement;

event.target 和event.currentTarget的区别:前者是触发事件的最终目标,后者是绑定事件时的目标。

借用事件代理的例子:

<div class="btn" onclick="console.log('onclick')">
        <span>sss</span>

</div>

  1. document.querySelector('.btn').addEventListener('click', function (e) {
  2. console.log('False currentTarget: ' + e.currentTarget.nodeName);
  3. console.log('False target: ' + e.target.nodeName);
  4. console.log(e.eventPhase);
  5. console.log(this);
  6. }, false);

2. 取消默认行为 & 阻止事件冒泡

  1. DOM:
  2. event.preventDefault();
  3. event.stopPropagation();
  4. IE8以下:
  5. event.returnValue = false;
  6. event.cancelBubble = true;

return false方式:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title></title>
  6. <script src="http://cdn.bootcss.com/jquery/1.11.0/jquery.js"></script>
  7. </head>
  8. <body>
  9.  
  10. <div onclick="alert('Outer clicked')">
  11. Outer Div<br><br>
  12. <a id="inner" href="http://www.google.com" onclick="return false;">Google</a>
  13. <script>
  14. document.getElementById('inner').addEventListener('click', function(e){
  15. alert(e.type);
  16. e.stopPropagation();
  17. return false;
  18. }, false);
  19. document.getElementById('inner').onclick = function(e){
  20. alert(e.type);
  21. e.stopPropagation();
  22. return false;
  23. };
  24.  
  25. $('#inner').click(function (e) {
  26. return false;
  27. });
  28. </script>
  29. </div>
  30. </body>
  31. </html>

在没有使用jquery的情况下,return false这种方式只有在DOM0的方式时可以相当于阻止默认行为的方法,DOM2级事件是不起任何效果的。

如果在jquery环境,return false相当于阻止默认行为和冒泡行为的方法,因为jquery本身的定义。

参考资料:

1. 前端工程师手册

js事件浅析的更多相关文章

  1. Node.js事件的正确使用方法

    前言 事件驱动的编程变得流行之前,在程序内部进行通信的标准方法非常简单:如果一个组件想要向另外一个发送消息,只是显式地调用了那个组件上的方法.但是在 react 中用的却是事件驱动而不是调用. 事件的 ...

  2. dynamic-css 动态 CSS 库,使得你可以借助 MVVM 模式动态生成和更新 css,从 js 事件和 css 选择器的苦海中脱离出来

    dynamic-css 使得你可以借助 MVVM 模式动态生成和更新 css,从而将本插件到来之前,打散.嵌套在 js 中的修改样式的代码剥离出来.比如你要做元素跟随鼠标移动,或者根据滚动条位置的变化 ...

  3. 什么是JS事件冒泡?

    什么是JS事件冒泡?: 在一个对象上触发某类事件(比如单击onclick事件),如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,如果没有定义此事件处理 程序或者事件返回true,那么 ...

  4. js事件技巧方法整合

    window.resizeTo(800,600); //js设置浏览器窗口尺寸 window.open (function(){ resizeTo(640,480);//设置浏览器窗口尺寸 moveT ...

  5. js 事件大全

    Js事件大全一般事件 事件 浏览器支持 描述onClick IE3|N2|O3 鼠标点击事件,多用在某个对象控制的范围内的鼠标点击onDblClick IE4|N4|O 鼠标双击事件onMouseDo ...

  6. 原生JS事件绑定方法以及jQuery绑定事件方法bind、live、on、delegate的区别

    一.原生JS事件绑定方法: 1.通过HTML属性进行事件处理函数的绑定如: <a href="#" onclick="f()"> 2.通过JavaS ...

  7. JS事件

    JS事件:  声明:为了事件对象event跨浏览器兼容: var oEvent==ev||event;      所以在下面用到 event 的地方都用 oEvent 代替  1)doucument的 ...

  8. 原生js事件和jquery事件的执行顺序问题

    场景:近日,写前端页面时候,在针对输入框input操作时,用到了jquery的插件,插件中使用了jquery的focus()和blur()方法.但是同时,又需要在插件之外再针对输入框的获取焦点和失去焦 ...

  9. 特殊js事件

    1:点击enter事件 $(document).keypress(function(e) { // 回车键事件 if(e.which == 13) { submitForm(); } }); 2:JQ ...

随机推荐

  1. SQL Server 更改跟踪(Chang Tracking)监控表数据

    一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 主要区别与对比(Compare) 实现监控表数据步骤(Process) 参考文献(Refere ...

  2. LINQ系列:LINQ to SQL Join连接

    1. 一对多 var expr = context.Products .Where(p => p.Category.CategoryName == "LINQ to SQL" ...

  3. OpenCASCADE Gauss Integration

    OpenCASCADE Gauss Integration eryar@163.com Abstract. Numerical integration is the approximate compu ...

  4. WPF textblock加入超链接

    <TextBlock Grid.Row=" Margin="75,0,0,0"> <Hyperlink Name="BlogHl" ...

  5. [汇编与C语言关系]5. volatile限定符

    现在研究一下编译器优化会对生成的指令产生什么影响,在此基础上介绍C语言的volatile限定符.首先看下面的C程序: /* artificial device registers */ unsigne ...

  6. [转]自己写PHP扩展之创建一个类

    原文:http://www.imsiren.com/archives/572 比如我们要创建一个类..PHP代码如下 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...

  7. .Net 转战 Android 4.4 日常笔记(8)--常见事件响应及实现方式

    在Andrioid开发中,常见的事件如下 单击事件 OnClickListener 长按事件 OnLongClickListener 滑动事件 OnTouchListenner 键盘事件 OnKeyL ...

  8. Web APi之捕获请求原始内容的实现方法以及接受POST请求多个参数多种解决方案(十四)

    前言 我们知道在Web APi中捕获原始请求的内容是肯定是很容易的,但是这句话并不是完全正确,前面我们是不是讨论过,在Web APi中,如果对于字符串发出非Get请求我们则会出错,为何?因为Web A ...

  9. 应用程序框架实战十四:DDD分层架构之领域实体(基础篇)

    上一篇,我介绍了自己在DDD分层架构方面的一些感想,本文开始介绍领域层的实体,代码主要参考自<领域驱动设计C#2008实现>,另外参考了网上找到的一些示例代码. 什么是实体 由标识来区分的 ...

  10. Hawk 数据抓取工具 使用说明(二)

    1. 调试模式和执行模式 1.1.调试模式 系统能够通过拖拽构造工作流.在编辑流的过程中,处于调试模式,为了保证快速地计算和显示当前结果(只显示前20个数据,可在调试的采样量中修改),此时,所有执行器 ...