当用户与浏览器发生的一些交互时, 若是但愿去得到用户行为, 就须要借助事件来完成. 事件部份内容在 JS中重要性不言而喻. html
罗列须要了解与事件相关的知识以下: 这也是面试中遇到的问题.面试
要想明白事件流,必须先懂的这几个知识点后端
先来看一个有趣的问题, 这是 4
代浏览器(IE4)开发团队遇到一个的问题:浏览器
What part of the Webpage owns a specific event?
页面的哪一部分会拥有某个特定的事件?框架
要想明白这个问题能够想象成在一个页面上画了一组同心圆, 当手指放在中间时,它不只在一个圆圈内,并且在全部的圆圈内。
以下图所示:函数
这就是浏览器事件的工做原理, 当你点击一个按钮时, 不只单击按钮,还单击包含的容器和整个页面。工具
事件生命周期, 分为三个阶段: capturing
(捕获), target
(目标), bubbling
(冒泡). 而这三个阶段也是构成事件流基本部分. 开发工具
这种处理思想, 在如今流行 NodeJS
后端框架 Koa
对中间件的处理模式也是基于这种, 熟悉Koa
或许对这洋葱图
并不会陌生:this
先来熟悉事件的模型:spa
事件冒泡: 既事件开始由最具体的元素接收,而后逐级向上传播最后到达 Document 对象 或 window 上.
先来看一个简单的示例, 代码以下:
<!DOCTYPE HTML> <html> <head> <title>......</title> </head> <body> <div id="demo"> Press here.</div> </body> </html>
var target = document.getElementById("demo"); window.addEventListener("click", function(){ console.log("window bubbling"); }); document.addEventListener("click", function(){ console.log("document bubbling"); }); document.documentElement.addEventListener("click", function(){ console.log("html bubbling"); }); document.body.addEventListener("click", function(){ console.log("body bubbling"); }); target.addEventListener("click", function(){ console.log("target bubbling"); });
控制台打印输出以下:
"target bubbling" "body bubbling" "html bubbling" "document bubbling" "window bubbling"
当一个div
被点击, 这点击事件发生的顺序以下:
从执行顺序来讲, click事件
首先在 div
元素上触发, 而后沿着DOM Tree 向上传播, 在路径上的每一个节点上触发,直到它到达文档对象(或Window对象)。
事件捕获
是另一种事件流模型, 最早由 Netscape Browser 引入.
根据上面的的模型, 恰好与前面冒泡相反. 根据该模型,最不特定(最外层)的节点首先接收事件,而最特定(目标元素)的节点最后接收事件.
它设计的目标就是在事件到达目标以前,事先进行拦截.
参考前面的示例, 修改下监听方式, 代码修改以下:
var target = document.getElementById("demo"); window.addEventListener("click", function(){ console.log("window Capturing"); }, true); document.addEventListener("click", function(){ console.log("document Capturing"); }, true); document.documentElement.addEventListener("click", function(){ console.log("html Capturing"); }, true); document.body.addEventListener("click", function(){ console.log("body Capturing"); }, true); target.addEventListener("click", function(){ console.log("target Capturing"); }, true);
打印的结果:
"window bubbling" "document bubbling" "html bubbling" "body bubbling" "target bubbling"
当点击 div
元素, 按照以下顺序来进行广播事件.
注意:
DOM0
级中默认就是使用冒泡的方式, 不支持捕获的. 因此在DOM2
级中经过addEventListener
提供的第三个参数来控制使用哪一种事件流来处理.
根据上面两种模型, 能够总结完整事件流应该向以下:
DOM Level 2 Events 指定的事件流模型分为三个阶段:
从上面流程图中, 首先发生的是 事件捕获阶段
为截获事件提供了机会, 再到目标阶段
而后进入 事件冒泡阶段
, 能够在这个阶段对事件进行响应.
引用
前面的例子, 点击 DIV
元素时, 事件将按照上图顺序进行触发.
这就是完整的事件流, 内容看起来挺多的, 实际上一句话就概述事件流.
用来描述事件发生顺序(页面接收事件顺序).
经过前面的知识点, 事件
就是表示用户或浏览器自身执行某种动做. 例如: click
, dbclick
, load
, unload
, mouseover
,mouseout
, mouseenter
,mouseleave
等等, 这些都是事件的名字
. 而响应并处理某个事件的函数称为 事件处理程序(或事件监听器(观察者模式))
.
常见事件处理方式包括以下几种:
直接来看个简单示例:
<input type="button" onclick="alert('<Clicked')"/>
这种模式, 能够理解为 CSS 行内样式
,
<div style="color: #ccc;"></div>
直接在 HTML 元素上绑定相应事件名, 并指定对应的事件处理程序. 从前面语法来讲, 事件处理程序是一个函数
, 上面传递是一个语句, 也就是说默认执行时, JS引擎会进行相应处理. 等价于这种方式:
<input type="button" onclick="(function(){alert('Clicked')})()"/>
若是把事件处理函数直接以这种内联值
的方式提供, 应该注意不能值中指定未经转义的HTML语法字符
例如: 和号(&) 、双引号("") 等等, 不然会解析出错.
如上面示例,若是想使用双引号, 必须这么处理.
<input type="button" onclick="alert("Clicked")"/>
这种对于简单语句还行, 除了提供元素属性值的方式, 那么有木有其它方式咧? 答案:固然有 , HTML事件处理程序能够调用在页面其它地方定义的脚本.
示例以下:
<input type="button" onclick="handleClick()"/> <script> function handleClick(){ alert("Clicked"); } </script>
经过这种方式指定事件处理程序具备一些特别的地方.
event
, 也就是事件对象.<input type="button" onclick="alert(event)"/> // => 等价 <input type="button" onclick="(function(){var e = event; alert(e);})()"/>
this
指针表示是当前的目标对象<input type="button" onclick="alert(this)"/> // this === [object HTMLInputElement] === input元素
这样能够经过 this
来获取目标元素相关的内容了. 好比取值
<input type="button" onclick="alert(this.value)"/> <!--或简写成这样--> <input type="button" value="Click Me" onclick="alert(value)"/>
为何能够简写方式, input 对象是存在于当前函数的做用域链中(scope). 为了调试方式, 把上面方式做以下改变
<input type="button" value="Click Me" onclick="(function aa(){debugger;console.log(value)})()"/>
其实理解上面那句话, 咱们能够借助开发这工具来协助理解:
input
对象会被添加在当前匿名函数执行的做用域链上.根据开发工具来看, 咱们是能够模拟引擎帮作的事情, 伪代码以下:
function () { with(document) { with(input){ // dosomething console.log(value); } } }
本质经过 with
来扩展做用域.
上面把基本内容说, 那么这种经过HTML事件处理程序有什么问题么 ?
事件处理程序必须优先元素加载, 有可能DOM加载出来, 用户就开始操做, 此时事件处理程序可能未加载致使报错
引用前面的示例:
<input type="button" onclick="handleClick()"/> <script> function handleClick(){ alert("Clicked"); } </script>
若是用户想把函数名为: "onClick", 这时是否是须要同时去修改.
未完, 后续...