0120-浏览器事件
Javascript和HTML的交互都是通过事件来实现的,而事件的产生与执行则是遵循着传统软件工程领域中的观察者模式,其能够做到页面行为和页面展示的解耦合。 本节内容会从事件流谈起,然后逐一介绍几种注册事件的方式以及他们其中的一些细节,最后还会提到关于**事件委托(代理)**的概念。 事件流 事件流描述了页面接受事件的顺序。因为一个事件的触发可能会影响好几处地方,这很容易理解,比如在页面上嵌套着写了几个div元素,同时在最里层的div元素上进行事件触发,那这不仅仅是最内层的div对事件进行响应,任意一层的嵌套的div都会对事件进行相应处理。(其实通过上述的观察者模式也可以推断出其合理性,因为一个对象可以由多个观察者进行观察) 所以多个监听事件的元素响应顺序需要进行统一,因为一些历史原因,事件的响应顺序有两种模式:冒泡和捕获。 事件冒泡 顾名思义,事件的冒泡就如水底下的气泡一下,从内到外,同理,事件冒泡规定的事件流顺序也是从内而外,事件会从最深层的节点开始触发,然后向外传播到document(文档)。 代码如下所示。 <html> <body> <div id="ddd"> click me </div> </body> </html> 此时我如果对id=ddd的div元素进行click事件触发,那么该事件会以如下顺序发生: div body html document 现代的浏览器的事件会一直冒泡到window对象。 事件捕获 事件捕获则和事件冒泡相反,事件的响应顺序是从外到内的,还是以上一个例子为例,那么对应click事件讲会以如下顺序发生: document html body div DOM事件流 DOM2 Events规范里规定里事件流为分三个部分:事件捕获,到达目标和事件冒泡。 需要注意的是,div元素(即直接触发元素)是不会响应捕获事件的,因为通常认为直接触发事件是冒泡阶段发生的,所以它也是冒泡阶段第一个发生的事件。 但现在大多数支持DOM事件流的浏览器都实现了一个小小的拓展,即在捕获阶段在事件目标上触发事件。最终结果表现为有两个机会来处理事件。 事件处理程序 事件意味着用户或浏览器执行的某种动作,而为响应事件而调用的函数被称为事件处理程序(事件监听器)。 HTML事件处理程序 HTML事件处理程序是以HTML属性的形式来进行指定的。该属性的值必须是能够执行的javascript代码。 比如下面这个例子,就是按钮在被点击时执行一段代码。 <button onclick="console.log('click')"> click me </button> 当然也可以以函数的形式来进行响应事件定义。 <script> function click(event){ console.log('click') } </script> <button onclick="click(event)"> click me </button> 可以看到,除了把函数单独拎出来以外,还多了一个event对象,这个是一个特殊的局部变量,它定义了事件触发的一些属性以及被触发元素的一些属性。 除此之外,HTML事件处理程序中的this就是DOM元素本身,所以可以直接使用this对象去获取对应元素上的属性。 <input type="button" value="Click Me" onclick="console.log(this.value)"> 这里还有个比较有趣的地方,获取元素属性时可以直接省略掉this,直接使用value,即下面写法也能达到同样的效果。 <input type="button" value="Click Me" onclick="console.log(value)"> 因为这个包装函数在创建时其作用域链被with操作符给延长了,所以document和元素自身的成员都可以被当成局部变量来使用。 function() { with(document) { with(this) { // 属性值 } } } 但最好不要这样做,因为不仅仅会显得很诡异,而且在后期调试时也会造成误解。 HTML事件处理程序一个比较大的问题是:它把HTML和Javascript在代码上进行了强耦合(在逻辑上依然是分开的),如果我们需要更改响应程序,那么两处都需要进行修改。...