JS事件类型可以分为三种:

  鼠标事件,由某个鼠标动作引发。常用的有click、mouseover、mouseout、mousedown、mouseup、dbclick、mousemove等;

  键盘事件,由某个键盘动作引发。常用的有keydown、keypress、keyup;

  接口事件,由用户行为的结果引起的事件,而非由用户行为直接引起的;如按下表单的submit按钮,会引起submit事件,由用户点击a链接时会要开新页面并释放当前页,些时会引起unload事件等,常用的有blur、focus、change、contextmenu、load、unload、readystatechange、reset、submit、resize、scroll等。

  一旦我们决定使用何种事件来完成交互时所需要做的事情时,就需要注册事件处理程序,事件注册方式有两种模型:

  传统模型

  行内作为属性。即直接在HTML元素通过添加属性形式来注册,优点是所有浏览器都兼容,缺点是维护难,违背了结构与行为相分离的WEB标准原则,所以不提倡,代码像这样:

  do

  

test

  值得注意的是大小写的问题,由于HTML对大小写不敏感,所以在过去编写这些事件时按惯例采用的驼峰格式像这样onClick、onMouseOver,但是值得注意的是作为元素的属性写在HTML里这样没有问题,但是如果是在在js环境里这样是不行的,因为js对大小敏感。

  结构与行为分离

  结构与行为分离的方式是遵循了WEB标准,要想分离必须设置关联钩子,像这样:

  do

  

test

  

  需要注意的是这里的函数名后面没有加(),加了表示立即执行,有时候我们想在页面加载完就立即执行一次那就需要加()。还有就是大小写的问题,之前也提到过了,这里的事件名字要小写像这样onclick,否则无法识别。当然还支持另一种形式即匿名函数,像这样:

var link=document.getElementById('link'),
  test=document.getElementById('test');
  link.onclick=function(){...};
  test.onclick=function(){...};

  虽然我们大部分时候都是用的这种传统方式,而且也不会发生什么错误,但它还是有它的缺点,那就是覆盖问题,按照代码从上往下的执行顺序,如果一个对象注册了相同的几个事件,那么最后的一个会把前面定义的事件全部覆盖,建议在项目完全由我们自己掌控的情况下可以使用些方法,无兼容性,且简单直观。如需要解决覆盖问题请看下面的高级事件注册模型。

  高级模型

  此模型主要用来有效解决覆盖问题,但是它有一个兼容性问题,即IE浏览器与其它WEB标准浏览器的事件注册方法不一样,幸运的是,解决这个兼容性问题并不难,我们先看看W3C(WEB标准浏览器阵容支持)和微软(IE系列阵容支持)所支持的高级事件处理程序方法:

 

obj.addEventListener('click', doThis, false); //添加
  obj.removeEventListener('click', doThis, false); //移除
  //Microsoft
  obj.attachEvent('onclick', doThis); //添加
  obj.detachEvent('onclick', doThis); //移除

  上面的代码我们可以看出,W3C提供的addEventListener和removeEventListener方法有三个参数:

  第一个是事件名称,它是字符串类型的;

  第二个是事件发生后要执行的函数,通常我们是不需要立即执行的,所以不带();

  第三个参数接收的是一个布尔值,指定事件传递的方式,false表示冒泡,true表示事件捕获。

  Microsoft提供的attachEvent和detachEvent方法有两个参数:

  第一参数是事件名称,它是字符串类型的,但和W3C不同的是微软它的事件名称需要加上on,和普通模型一样的;

  第二参数是事件发生后要执行的函数,和W3C一样

  我们可以写个两个通用函数来解决兼容性问题,像这样:

  注册事件

 

addEventSimple(obj, evt, fn, bool){
  //对象检测,通常都是将W3C制定的方法判断在前面,因为那些暂时不支持的浏览器或许哪一天就跟随标准了,放在前面这也是提升性能的小技巧
  if(obj.addEventListener){
  bool=bool || false;
  obj.addEventListener(evt, fn, bool);
  }else if(obj.attachEvent){
  obj.attachEvent('on'+evt, fn);
  }
  }
  //移移注册事件
  removeEventSimple(obj, evt, fn, bool){
  if(obj.removeEventListener){
  bool=bool || false;
  obj.removeEventListener(evt, fn, bool);
  }else if(obj.detachEvent){
  obj.detachEvent('on'+evt, fn);
  }
  }

  addEventSimple接受四个参数,其中前三个是必须的,第四个是可选的

  obj指定注册事件的对象,数据类型为Object;

  evt指定事件名称,数据类型为String;

  fn指定事件发生后要执行的函数;

  bool指定事件传递的类型,数据类型为Boolean;

  接下来我们就可以这样使用了:

  do

  

test

  

  这样就不会覆盖了,虽然事件注册高级模型,看似很牛B,但也有它的缺点,除了刚才所说的兼容性问题,还有一个就是它无法移除对象上同一个注册事件绑定的所有执行函数。如果需要移除就必须要知道对象事件注册绑定的执行函数名称如上面的doThis、doThat。而传统模型是可能的:obj.onclick=null。