自己封装的javascript事件队列函数版

  背景

  javascript中使用addEventListener()或attachEvent()绑定事件时会有几个小问题:

  一、使用addEventListener()或attachEvent()添加的匿名函数无法移除。

  

复制代码 代码如下:
var oBtn = document.getElementById('btn');

  oBtn.addEventListener('click',function(){

  alert('button is clicked')

  },false)

  oBtn.reomveEventListener('click',function(){

  alert('button is clicked')

  },false)

  //oBtn上的事件无法移除,因为传入的是一个匿名函数

  二、ie6-ie8中,使用attachEvent()绑定多个事件的倒序执行问题。

  

复制代码 代码如下:

  var oBtn = document.getElementById('btn');

  oBtn.attachEvent('onclick',function(){

  alert(1)

  })

  oBtn.attachEvent('onclick',function(){

  alert(2)

  })

  oBtn.attachEvent('onclick',function(){

  alert(3)

  })

  //ie9+   下执行顺序1、2、3

  //ie6-ie8下执行顺序3、2、1

  解决问题

  我想写一个跨浏览器的事件绑定模块,这样以后可以复用,同时我想解决上诉问题。JQuery内部使用事件队列和数据缓存机制解决此问题,看了下相关源码,实在复杂,自个试了一些方法,勉强实现。贴段代码,原来是用面向对象写的,不想让人看得很复杂,所有改成函数来组织。

  

复制代码 代码如下:

  /*绑定事件的接口

  *

  *@param    {dom-DOM}和{type-string}和{fn-function}  可选参数{fnName-string}

  *@execute  创建事件队列,添加到DOM对象属性上,

  将事件处理程序(函数)加入事件队列

  可为事件处理程序添加一个标识符,用于删除指定事件处理程序

  */

  function bind(dom,type,fn,fnName){

  dom.eventQueue = dom.eventQueue || {};

  dom.eventQueue[type] = dom.eventQueue[type] || {};

  dom.handler = dom.handler || {};

  if (!fnName) {

  var index = queueLength(dom,type);

  dom.eventQueue[type]['fnQueue'+index] = fn;

  }

  else {

  dom.eventQueue[type][fnName] = fn;

  };

  if (!dom.handler[type]) bindEvent(dom,type);

  };

  /*绑定事件

  *

  *@param    {dom-DOM}和{type-string}

  *@execute  只绑定一次事件,handler用于遍历执行事件队列中的事件处理程序(函数)

  *@caller   bind()

  */

  function bindEvent(dom,type){

  dom.handler[type] = function(){

  for(var guid in dom.eventQueue[type]){

  dom.eventQueue[type][guid].call(dom);

  }

  };

  if (window.addEventListener) {

  dom.addEventListener(type,dom.handler[type],false);

  }

  else {

  dom.attachEvent('on'+type,dom.handler[type]);

  };

  };

  /*移除事件的接口

  *

  *@param    {dom-DOM}和{type-string} 可选参数{fnName-function}

  *@execute  如果没有标识符,则执行unBindEvent()

  如果有标识符,则删除指定事件处理程序,如果事件队列长度为0,执行unBindEvent()

  */

  function unBind(dom,type,fnName){

  var hasQueue = dom.eventQueue && dom.eventQueue[type];

  if (!hasQueue) return;

  if (!fnName) {

  unBindEvent(dom,type)

  }

  else {

  delete dom.eventQueue[type][fnName];

  if (queueLength(dom,type) == 0) unBindEvent(dom,type);

  };

  };

  /*移除事件

  *

  *@param    {dom-DOM}和{type-string}

  *@execute  移除绑定的事件处理程序handler,并清空事件队列

  *@caller   unBind()

  */

  function unBindEvent(dom,type){

  if (window.removeEventListener) {

  dom.removeEventListener(type,dom.handler[type])

  }

  else {

  dom.detachEvent(type,dom.handler[type])

  }

  delete dom.eventQueue[type];

  };

  /*判断事件队列长度

  *

  *@param    {dom-DOM}和{type-string}

  *@caller   bind() unBind()

  */

  function queueLength(dom,type){

  var index = 0;

  for (var length in dom.eventQueue[type]){

  index++ ;

  }

  return index;

  };

  使用方法

  

复制代码 代码如下:

  var oBtn = document.getElementById('btn');

  //绑定事件

  //为button同时绑定三个click事件函数

  //ie6-ie8下执行顺序不变

  bind(oBtn,'click',function(){

  alert(1);

  })

  bind(oBtn,'click',function(){

  alert(2);

  },'myFn')

  bind(oBtn,'click',function(){

  alert(3);

  })

  //移除事件

  //移除所有绑定的click事件函数,支持移除匿名函数

  unBind(oBtn,'click')

  //只移除标识符为myfn的事件函数

  unBind(oBtn,'click','myFn')

  程序思路

  程序主要思路就像将事件队列作为dom元素对象的一个属性,添加在dom元素上,而不会污染全局环境,这样可以解决不同dom元素绑定不同事件类型的多个事件函数的数据存储问题。

  

复制代码 代码如下:

  //dom元素上的事件队列

  dom{

  eventQueue : {

  'click' : {

  fnQueue1 : function,

  myfn     : function,

  fnQueue3 : function

  }

  'mouseover' : {

  fnQueue1 : function,

  fnQueue2 : function

  }

  }

  }

  每次先把事件函数添加到对应事件类型的事件队列中,只绑定一次事件。触发事件时执行handler事件函数,handler则遍历执行事件队列中的事件函数。

  unBind()如果没有传入标识符,则移除所有绑定的事件函数,支持移除匿名函数,如果有标识符则移除指定的事件函数。

  程序逻辑并不复杂,可能有bug和性能问题,有兴趣可以指导交流下。