JS事件

事件

通过侦听器来预定事件

事件流

事件流描述的是从页面中接收事件的顺序
事件例图:

IE 的事件流是事件冒泡流

Netscape Communicator 的事件流是事件捕获流


事件冒泡

IE 的事件流叫做事件冒泡,即事件开始时由最具体的元素(文档中嵌套层次最深 的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。

事件捕捉

事件捕获的思想 是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。

DOM事件流

DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。

在 DOM 事件流中,实际的目标(元素)在捕获阶段不会接收到事件。这意味着在捕获阶段, 事件从 document 到再到后就停止了。下一个阶段是“处于目标”阶段,于是事件在上发生,并在事件处理(后面将会讨论这个概念)中被看成冒泡阶段的一部分。然后,冒泡阶段发生, 事件又传播回文档。


## 事件处理程序

事件就是用户或浏览器自身执行的某种动作。诸如 click、load 和 mouseover,都是事件的名字。 而响应某个事件的函数就叫做事件处理程序(或事件侦听器)

事件处理程序的名字以"on"开头(onclick,onload)

HTML事件处理程序

这个操作是通过指定 onclick 特性并将一些 JavaScript 代码作为它的值来定义的

<input type="button" value="Click Me" onclick="alert('Clicked')" /> 

为了避免使用 HTML 实体,这里使用了单 引号。如果想要使用双引号,那么就要将代码改写成如下所示:

<input type="button" value="Click Me" onclick="alert(&quot;Clicked&quot;)" /> 

事件处理程序中的代码在执行时,有权访问全局作用 域中的任何代码

<!-- 输出 "click" --> 
<input type="button" value="Click Me" onclick="alert(event.type)"> 

这样指定事件处理程序具有一些独到之处。首先,这样会创建一个封装着元素属性值的函数。这个 函数中有一个局部变量 event


通过 event 变量,可以直接访问事件对象,你不用自己定义它,也不用从函数的参数列表中读取。 在这个函数内部,this 值等于事件的目标元素

<!-- 输出 "Click Me" --> 
<input type="button" value="Click Me" onclick="alert(this.value)"> 

## HTML 中指定事件处理程序的缺点

1.存在一个时差问题。因为用户可能会在 HTML 元素一出现在页面上就触发相应的事件,但当时的事件处理程序有可能尚不具备执行条件。以前面的例子来说明,假设 showMessage()函数是在按钮下方、页面的最底部定义的。如果用户在页面解 析 showMessage()函数之前就单击了按钮就会引发错误。为此,很多 HTML 事件处理程序都会被封 装在一个 try-catch 块中,以便错误不会浮出水面,如下面的例子所示:

<input type="button" value="Click Me" onclick="try{showMessage();}catch(ex){}">

2.这样扩展事件处理程序的作用域链在不同浏览器中会导致不同结果。不同 JavaScript 引擎遵循的标识符解析规则略有差异,很可能会在访问非限定对象成员时出错。

3.是 HTML 与 JavaScript 代码紧密耦合。如果要更换事 件处理程序,就要改动两个地方:HTML 代码和 JavaScript 代码

DOM0 级事件处理程序

通过 JavaScript 指定事件处理程序的传统方式

原因一是简单,二是具有跨浏览器的优势

要使用 JavaScript 指定事件处理程序,首先必须取得一 个要操作的对象的引用


使用 DOM0 级方法指定的事件处理程序被认为是元素的方法。因此,这时候的事件处理程序是在 元素的作用域中运行;换句话说,程序中的 this 引用当前元素

var btn = document.getElementById("myBtn"); 
btn.onclick = function(){ 
alert(this.id); //"myBtn" 
};

btn.onclick = null; //删除事件处理程序

以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理

将事件处理程序设置为 null 之后,再单击按钮将不会有任何动作发生。



## DOM2 级事件处理程序

“DOM2级事件”定义了两个方法,用于处理指定和删除事件处理程序的操作:**addEventListener() **和 removeEventListener()

它们都接受 3 个参数:要处 理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数如果是 true,表示在捕获 阶段调用事件处理程序;如果是 false,表示在冒泡阶段调用事件处理程序

在按钮上为 click 事件添加事件处理程序

var btn = document.getElementById("myBtn"); 
btn.addEventListener("click", function(){ 
 alert(this.id); 
}, false); 

上面的代码为一个按钮添加了 onclick 事件处理程序,而且该事件会在冒泡阶段被触发

var btn = document.getElementById("myBtn"); 
btn.addEventListener("click", function(){ 
 alert(this.id); 
}, false); 
btn.addEventListener("click", function(){ 
 alert("Hello world!"); 
}, false); 

这里为按钮添加了两个事件处理程序。这两个事件处理程序会按照添加它们的顺序触发,因此首先 会显示元素的 ID,其次会显示"Hello world!"消息

通过 addEventListener()添加的事件处理程序只能使用 removeEventListener()来移除,这也意味着通过 addEventListener()添加的匿 名函数将无法移除。

var btn = document.getElementById("myBtn"); 
btn.addEventListener("click", function(){ 
 alert(this.id)}, false); 
//这里省略了其他代码
btn.removeEventListener("click", function(){ //没有用!
 alert(this.id); 
}, false); 

传入 removeEventListener()中的事件处理程序函数必须与传入 addEventListener()中的相同 ,因为一一对应,addEvenListener()可以给click或其他添加很多函数,所以removeEvenListener()也要一一去和它对应

大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段(f第三个参数为false),这样可以最大限度地兼容各种浏览器。

事件对象

在触发 DOM 上的某个事件时,会产生一个事件对象 event,这个对象中包含着所有与事件有关的 信息。

DOM中的事件对象

兼容 DOM 的浏览器会将一个 event 对象传入到事件处理程序中

var btn = document.getElementById("myBtn"); 
btn.onclick = function(event){ 
 alert(event.type); //"click" 
}; 
btn.addEventListener("click", function(event){ 
 alert(event.type); //"click" 
}, false);

要阻止特定事件的默认行为,可以使用 preventDefault()方法

链接的默认行为就是在 被单击时会导航到其 href 特性指定的 URL。如果你想阻止链接导航这一默认行为,那么通过链接的 onclick 事件处理程序可以取消它

var link = document.getElementById("myLink"); 
link.onclick = function(event){ 
 event.preventDefault(); 
};

stopPropagation()方法用于立即停止事件在 DOM 层次中的传播

从而避免触 发注册在 document.body 上面的事件处理程序

var btn = document.getElementById("myBtn"); 
btn.onclick = function(event){ 
 alert("Clicked"); 
 event.stopPropagation(); 
}; 
document.body.onclick = function(event){ 
 alert("Body clicked"); 
}; 

事件类型


load事件

当页面完全加载后(包括所有图像、JavaScript 文件、 CSS 文件等外部资源),就会触发 window 上面的 load 事件。

<body onload="alert('Loaded!')"> 
</body>

//对图像的load事件
<img src="smile.gif" onload="alert('Image loaded.')"> 

unload 事件

利用这个事件最多的情况是清除引用,以避免内存泄漏

resize 事件

当浏览器窗口被调整到一个新的高度或宽度时,就会触发 resize 事件

IE、Safari、Chrome 和 Opera 会在浏览 器窗口变化了 1 像素时就触发 resize 事件,然后随着变化不断重复触发。Firefox 则只会在用户停止调 整窗口大小时才会触发 resize 事件

浏览器窗口最小化或最大化时也会触发 resize 事件

scroll 事件

scroll 事件也会在文档被滚动期间重复被触发,所以有必要尽量保持事件 处理程序的代码简单

焦点事件

焦点事件会在页面元素获得或失去焦点时触发。利用这些事件并与 document.hasFocus()方法及 document.activeElement 属性配合,可以知晓用户在页面上的行踪

  • blur

    在元素失去焦点时触发。这个事件不会冒泡;所有浏览器都支持它

  • DOMFocusIn

    在元素获得焦点时触发。这个事件与 HTML 事件 focus 等价,但它冒泡

  • DOMFoucusOut

    在元素失去焦点时触发,兼容性不强

  • focus

    在元素获得焦点时触发。这个事件不会冒泡;所有浏览器都支持它。

  • focusin

    这个事件与 HTML 事件 focus 等价,但它冒泡

  • focusout

    这个事件是 HTML 事件 blur 的通用版本

鼠标与滚轮事件

  • click

    在用户单击主鼠标按钮(一般是左边的按钮)或者按下回车键时触发。

  • dblclick

    在用户双击主鼠标按钮(一般是左边的按钮)时触发。

  • mousedown

    在用户按下了任意鼠标按钮时触发。不能通过键盘触发这个事件。

  • mouseenter

    在鼠标光标从元素外部首次移动到元素范围之内时触发。这个事件不冒泡,而且 在光标移动到后代元素上不会触发。

  • mouseleave

    在位于元素上方的鼠标光标移动到元素范围之外时触发。这个事件不冒泡,而且 在光标移动到后代元素上不会触发。

  • mousemove

    当鼠标指针在元素内部移动时重复地触发。

  • mouseout

    在鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发。

  • mouseover
    在鼠标指针位于一个元素外部,然后用户将其首次移入另一个元素边界之内时触 发。

  • mouseup

    在用户释放鼠标按钮时触发。