{"action":"opened","issue":{"url":"https://api.github.com/repos/mrzqii/blog/issues/5","repository_url":"https://api.github.com/repos/mrzqii/blog","labels_url":"https://api.github.com/repos/mrzqii/blog/issues/5/labels{/name}","comments_url":"https://api.github.com/repos/mrzqii/blog/issues/5/comments","events_url":"https://api.github.com/repos/mrzqii/blog/issues/5/events","html_url":"https://github.com/mrzqii/blog/issues/5","id":364383331,"node_id":"MDU6SXNzdWUzNjQzODMzMzE=","number":5,"title":"关于DOM事件流的三个阶段","user":{"login":"mrzqii","id":33239931,"node_id":"MDQ6VXNlcjMzMjM5OTMx","avatar_url":"https://avatars3.githubusercontent.com/u/33239931?v=4","gravatar_id":"","url":"https://api.github.com/users/mrzqii","html_url":"https://github.com/mrzqii","followers_url":"https://api.github.com/users/mrzqii/followers","following_url":"https://api.github.com/users/mrzqii/following{/other_user}","gists_url":"https://api.github.com/users/mrzqii/gists{/gist_id}","starred_url":"https://api.github.com/users/mrzqii/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrzqii/subscriptions","organizations_url":"https://api.github.com/users/mrzqii/orgs","repos_url":"https://api.github.com/users/mrzqii/repos","events_url":"https://api.github.com/users/mrzqii/events{/privacy}","received_events_url":"https://api.github.com/users/mrzqii/received_events","type":"User","site_admin":false},"labels":[{"id":1070955761,"node_id":"MDU6TGFiZWwxMDcwOTU1NzYx","url":"https://api.github.com/repos/mrzqii/blog/labels/html","name":"html","color":"008672","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2018-09-27T09:27:38Z","updated_at":"2018-09-27T09:27:38Z","closed_at":null,"author_association":"OWNER","body":"### 什么是事件流？\r\n> 事件流描述的是从页面中接收事件的顺序。但有意思的是，IE 和 Netscape 开发团队居然提出了差 不多是完全相反的事件流的概念。IE的事件流是事件冒泡流，而 Netscape Communicator的事件流是事 件捕获流。 \r\n\r\n- #### 事件冒泡\r\n\r\nIE的事件流叫做事件冒泡（event bubbling），即事件开始时由具体的元素（文档中嵌套层次深 的那个节点）接收，然后逐级向上传播到较为不具体的节点（文档）\r\n- #### 事件捕获 \r\n\r\nNetscape Communicator团队提出的另一种事件流叫做事件捕获（event capturing）。事件捕获的思想 是不太具体的节点应该更早接收到事件，而具体的节点应该后接收到事件。事件捕获的用意在于在 事件到达预定目标之前捕获它。\r\n\r\n- #### DOM事件流 \r\n“DOM2级事件”规定的事件流包括三个阶段：事件捕获阶段、处于目标阶段和事件冒泡阶段。首 先发生的是事件捕获，为截获事件提供了机会。然后是实际的目标接收到事件。后一个阶段是冒泡阶 段，可以在这个阶段对事件做出响应。\r\n\r\n举例说明：\r\n```\r\n<body>\r\n    <div id=\"div1\">\r\n        <button id=\"btn\">按钮</button>\r\n    </div>\r\n<script>\r\n    var btn = document.getElementById(\"btn\");\r\n    var div1 = document.getElementById(\"div1\");\r\n    \r\n    //事件捕获\r\n    window.addEventListener(\"click\",function(){\r\n        console.log(\"捕获4.Click window\");\r\n    },true);\r\n    document.addEventListener(\"click\",function(){\r\n        console.log(\"捕获3.Click document\");\r\n    },true);\r\n    document.body.addEventListener(\"click\",function(){\r\n        console.log(\"捕获2.Click body\");\r\n    },true);\r\n    div1.addEventListener(\"click\",function(){\r\n        console.log(\"捕获1.5 Click div1\");\r\n    },true);\r\n    \r\n    btn.addEventListener(\"click\",function(){\r\n        console.log(\"捕获1.Click btn\");\r\n    },true);\r\n    \r\n    这里注意：btn在捕获阶段注册了事件，在冒泡阶段也注册了事件，那他们的执行就是 哪个事件先注册就先执行哪一个\r\n    \r\n    //事件冒泡\r\n    btn.onclick = function(){\r\n        console.log(\"冒泡1.Click btn\");\r\n        \r\n        event.stopPropagation(); 事件冒泡是可以被阻止的！！！！！！\r\n    }\r\n    div1.onclick = function(){\r\n        console.log(\"冒泡1.5 Click div1\");\r\n    }\r\n    document.body.onclick = function(){\r\n        console.log(\"冒泡2.Click Body\");\r\n    }\r\n    document.onclick = function(){\r\n        console.log(\"冒泡3.Click document\");\r\n    }\r\n    window.onclick = function(){\r\n        console.log(\"冒泡4.Click window\");\r\n    }\r\n\r\n    \r\n</script>\r\n\r\n</body>\r\n\r\n结果为：\r\n\r\n\"捕获4.Click window\"\r\n\"捕获3.Click document\"\r\n\"捕获2.Click body\"\r\n\"捕获1.5 Click div1\"\r\n\"捕获1.Click btn\"\r\n\"冒泡1.Click btn\"\r\n\"冒泡1.5 Click div1\"\r\n\"冒泡2.Click Body\"\r\n\"冒泡3.Click document\"\r\n\"冒泡4.Click window\"\r\n```\r\n\r\n---\r\n```\r\n阻止事件冒泡的通用写法\r\n\r\nfunction preventBubble(event){  \r\n    var e=arguments.callee.caller.arguments[0]||event; //若省略此句，下面的e改为event，IE运行可以，但是其他浏览器就不兼容  \r\n    if (e && e.stopPropagation) {    \r\n        e.stopPropagation();\r\n    } else if (window.event){    \r\n        window.event.cancelBubble = true;\r\n    }\r\n}\r\n \r\n```\r\n\r\n- #### DOM0 级事件处理程序-1 \r\n将一个函数赋值给一个事件处理程序属性。这种为事件处理程序赋值的方法是在第四代 Web 浏览器中出现的，而且至今仍然为所有现代浏览器所支持。原因一是简单，二是具有跨浏览器的优势。要使用 JavaScript 指定事件处理程序，首先必须取得一个要操作的对象的引用。 每个元素（包括 window 和 document）都有自己的事件处理程序属性，这些属性通常全部小写， 例如 onclick。将这种属性的值设置为一个函数，就可以指定事件处理程序\r\n\r\n- #### DOM2 级事件处理程序-2\r\n\r\n“DOM2级事件”定义了两个方法，用于处理指定和删除事件处理程序的操作：addEventListener() 和 removeEventListener()。所有 DOM节点中都包含这两个方法，并且它们都接受 3个参数：要处 理的事件名、作为事件处理程序的函数和一个布尔值。后这个布尔值参数如果是 **true**，表示在**捕获 阶段**调用事件处理程序；如果是 **false**，表示在**冒泡阶段**调用事件处理程序。 \r\n\r\n\r\n\r\n- #### IE事件处理程序 -3\r\nIE实现了与 DOM中类似的两个方法：attachEvent()和 detachEvent()。这两个方法接受相同 的两个参数：事件处理程序名称与事件处理程序函数。由于 IE8 及更早版本只支持事件冒泡，所以通过 attachEvent()添加的事件处理程序都会被添加到冒泡阶段。 \r\n\r\n**关于上述三个处理程序的使用方法，我这里贴出一个经典的函数来说明使用方法以及取消事件的方法：**\r\n```\r\nvar EventUtil = {\r\n\taddEvent:function(element,type,handler){\r\n\t\tif(element.addEventListener){\r\n\t\t\telement.addEventListener(type,handler,false);\r\n\t\t}else if(element.attachEvent){\r\n\t\t\telement.attachEvent(\"on\"+type,handler);\r\n\t\t}else{\r\n\t\t\telement[\"on\"+type] = handler;\r\n\t\t}\r\n\t},\r\n\tremoveEvent:function(element,type,handler){\r\n\t\tif(element.removeEventListener){\r\n\t\t\telement.removeEventListener(type,handler,false);\r\n\t\t}else if(element.detachEvent){\r\n\t\t\telement.detachEvent(\"on\"+type,handler);\r\n\t\t}else{\r\n\t\t\telement[\"on\"+type] = null;\r\n\t\t}\r\n\t}\r\n};\r\n```\r\n\r\n参考: 《JavaScript高级程序设计》"}}
{"actor":{"display_login":"mrzqii"}}