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


Posted in Javascript onJune 12, 2014

背景

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和性能问题,有兴趣可以指导交流下。

Javascript 相关文章推荐
JavaScript中的私有成员
Sep 18 Javascript
使用JQuery进行跨域请求
Jan 25 Javascript
JavaScript 处理Iframe自适应高度(同或不同域名下)
Mar 29 Javascript
淘宝网提供的国内NPM镜像简介和使用方法
Apr 17 Javascript
Javascript常用字符串判断函数代码分享
Dec 08 Javascript
javascript 动态创建表格的2种方法总结
Mar 04 Javascript
AngularJS控制器之间的数据共享及通信详解
Aug 01 Javascript
Bootstrap源码解读排版(1)
Dec 23 Javascript
详细讲解vue2+vuex+axios
May 27 Javascript
JS使用队列对数组排列,基数排序算法示例
Mar 02 Javascript
javascript实现视频弹幕效果(两个版本)
Nov 28 Javascript
Vue Router的手写实现方法实现
Mar 02 Javascript
jquery动态添加删除一行数据示例
Jun 12 #Javascript
checkbox勾选判断代码分析
Jun 11 #Javascript
百度判断手机终端并自动跳转js代码及使用实例
Jun 11 #Javascript
js获取日期:昨天今天和明天、后天
Jun 11 #Javascript
js使用栈来实现10进制转8进制与取除数及余数
Jun 11 #Javascript
删除javascript中注释语句的正则表达式
Jun 11 #Javascript
Jquery自定义button按钮的几种方法
Jun 11 #Javascript
You might like
《魔兽世界》惊魂幻象将获得调整
2020/03/08 其他游戏
php简单对象与数组的转换函数代码(php多层数组和对象的转换)
2011/05/18 PHP
一个PHP验证码类代码分享(已封装成类)
2011/07/17 PHP
利用php绘制饼状图的实现代码
2013/06/07 PHP
php获取远程图片体积大小的实例
2013/11/12 PHP
windows下PHP_intl.dll正确配置方法(apache2.2+php5.3.5)
2014/01/14 PHP
使用PHP反射机制来构造"CREATE TABLE"的sql语句
2019/03/21 PHP
基于jquery的合并table相同单元格的插件(精简版)
2011/04/05 Javascript
深入理解JavaScript系列(3) 全面解析Module模式
2012/01/15 Javascript
js 控制图片大小核心讲解
2013/10/09 Javascript
js style动态设置table高度
2014/10/21 Javascript
举例详解AngularJS中ngShow和ngHide的使用方法
2015/06/19 Javascript
bootstrap栅格系统示例代码分享
2017/05/22 Javascript
angular实现图片懒加载实例代码
2017/06/08 Javascript
利用vue + koa2 + mockjs模拟数据的方法教程
2017/11/22 Javascript
vue+php实现的微博留言功能示例
2019/03/16 Javascript
微信小程序云开发之数据库操作
2019/05/18 Javascript
iview form清除校验状态的实现
2019/09/19 Javascript
JavaScript对象属性操作实例解析
2020/02/04 Javascript
一篇超完整的Vue新手入门指导教程
2020/11/18 Vue.js
Python编写检测数据库SA用户的方法
2014/07/11 Python
网站渗透常用Python小脚本查询同ip网站
2017/05/08 Python
Python中sort和sorted函数代码解析
2018/01/25 Python
Python中将dataframe转换为字典的实例
2018/04/13 Python
对tensorflow 的模型保存和调用实例讲解
2018/07/28 Python
Django视图扩展类知识点详解
2019/10/25 Python
python保留格式汇总各部门excel内容的实现思路
2020/06/01 Python
关于h5中的fetch方法解读(小结)
2017/11/15 HTML / CSS
写演讲稿所需要注意的4个条件
2014/01/09 职场文书
财产公证书样本
2014/04/04 职场文书
助学贷款贫困证明
2014/09/23 职场文书
党员民主评议总结
2014/10/20 职场文书
运动会3000米加油稿
2015/07/21 职场文书
解决pytorch 损失函数中输入输出不匹配的问题
2021/06/05 Python
JavaScript如何优化逻辑判断代码详解
2021/06/08 Javascript
六个好看实用的 HTML + CSS 后台登录入口页面
2022/04/28 HTML / CSS