2、 认清事件的本质
要想解决这个问题,我们就需要认识一下事件本身。其实onclick本身不是事件,click才是事件,同样onmouseover也不是事件,mouseover才是。
一个页面的html元素设置onclick这些属性的时候,有且只能设置一次,那我们就需要跳出设置onclick这个思维,从click上入手,直接给html元素添加click的事件处理,而且保证都是可以做到独立执行。
这里就需要引入window的一个方法了,不同浏览器的实现不一样,web标准中定义的window.addEventListener,但ie中相应的方法是window.attachEvent。2个方法能处理的事情都是一样的,只是具体的代码实现有点差别。
那我们就看一个具体的示例,怎么给一个html元素添加事件吧。
<script>
var Event = function(){}
/**
* 给元素添加事件
* @param {Object} dom htmlElement对象
* @param {Object} eventName 事件的名称,不包含on
* @param {Object} callFunc 回调的函数
* @param {Object} scope 函数操作范围
* @param {Object} config 参数配置,这个必须为数组形式,eg:[1,"2"]等等
*/
Event.on = function(dom,eventName,callFunc,scope,config){
//如果已经添加过相同的事件函数,就不处理
/*var fn = ZERO.EventCache.get(dom,eventName,callFunc.getName());
if(fn){
return;
}*/
var scope = scope||window;
var config = config || [];
var h = function(e){
var evt = window.event || e;
callFunc.apply(scope,[evt].concat(config));
}
//ZERO.EventCache.set(dom,eventName,callFunc.getName(),h);
if(eventName == "mousewheel" && dom.addEventListener){
dom.addEventListener("DOMMouseScroll", h, false);
Event.on(window, 'unload', function(){
dom.removeEventListener("DOMMouseScroll", h, false);
});
}
else{
if(window.attachEvent){
dom.attachEvent("on"+eventName, h);
}
else if(window.addEventListener){
dom.addEventListener(eventName, h,false);
}
}
}
function ck(){
alert("成功定义了事件了,恭喜");
}
function addEvent(){
var el = document.getElementById("check");
Event.on(el,"click",ck);
}
</script>
<input id="check" type="button" value="空按钮"/>
<input type="button" value="给空按钮添加事件" onclick="addEvent();"/>
在点击“给空按钮添加事件”之前点击“空按钮”没有任何响应,点击之后就可以弹出对话框了,说明追加事件成功。如果点了2下“给空按钮添加事件”,这里就会弹出2次对话框,这也说明这个添加事件不会覆盖以前追加的事件,当然也不会影响onclick属性中定义的事件了。
(1) 添加事件分析
这里的添加事件本身Event.on()有5个参数,其中前3个参数是必须的,后面的2个是可配置的。
* @param {Object} dom htmlElement对象
* @param {Object} eventName 事件的名称,不包含on
* @param {Object} callFunc 回调的函数
其实最终事件触发执行的函数并不是callFunc本身,而是函数中内部定义的h这个函数。然后通过dom. addEventListener或者dom.attachEvent,绑定dom的事件函数。
但这个方法中会有缺陷:
a. 没有判断添加重复事件;
b. 事件添加之后没提供删除功能。
第一个缺陷比较容易理解,重复事件肯定是要防止的,那为什么要提第二个缺陷呢。在什么情况下需要删除事件呢,在事件所依赖的htmlElement从DOM树中移除。
(2) 阻止添加重复事件
针对第一个缺陷,在添加事件的时候我们需要利用cache把事件缓存下来,等到继续添加事件的时候,判断是否已经添加过相同的事件即可。
这个cache需要记录3部分信息,dom对象、事件名称、函数内容及名称。函数名称只需要传入函数对象本身即可,我们可以通过如下方法来简单获取函数名称。
Function.prototype.getName = function(){
var str = this.toString();
var className = str.substr(0, str.indexOf('('));
className = className.replace('function', '');
if(className.trim()==""){
return str;
}
return className.trim();
}
使用方法比较简单,例子:
function callback(){
//function body
}
callback.getName();
Event.on这个函数中有如下代码:
var fn = ZERO.EventCache.get(dom,eventName,callFunc.getName());
if(fn){
return;
}
这个就是用来判断是否有重复函数,当然在添加事件之后,需要进行set,
ZERO.EventCache.set(dom,eventName,callFunc.getName(),h);
这句话就是把事件定义保存起来,以便于进行重复、删除等操作的依据。
(3) 删除事件
事件追加之后,也必须要有退出机制才是完整的。要不然一个网页的内存消耗会越来越大,就不是一个好的web程序。
针对window.attatchEvent以及window.addEventListener,相应的也提供了,window.detachEvent及window.removeEventListener。
/**
* 把对应的事件删除掉
* @param {Object} dom
* @param {Object} eventName
* @param {Object} callFunc
*/
Event.un = function(dom,eventName,callFunc){
var fn = ZERO.EventCache.get(dom,eventName,callFunc.getName());
if(fn==null){
return;
}
if (window.removeEventListener) {
dom.removeEventListener(eventName, fn, false);
} else if (window.detachEvent) {
dom.detachEvent("on" + eventName,fn);
}
//最后需要将事件定义从cache中删除掉
ZERO.EventCache.remove(dom,eventName,callFunc.getName());
}
这里注意removeEventListener中的第二个参数不是直接传入callFunc呢。其实从Event.on我们就可以看出我们追加事件的时候也不是用callFunc,而是内部创建的函数h,我们已经把这个h放入cache了,删除事件的时候,只要从cache中找到这个h就可以了。
追加事件以及删除事件都用到了cache,给大家看一下这个cache的实现逻辑:
ZERO.EventCache = function(){
var cache = {};
return {
get : function(dom,eventName,name){
if(cache[dom] && cache[dom][eventName]){
return cache[dom][eventName][name];
}
return null;
},
set : function(dom,eventName,name,func){
if(cache[dom]){
if(cache[dom][eventName]){
cache[dom][eventName][name] = func;
}
else{
cache[dom][eventName] = {};
cache[dom][eventName][name] = func;
}
}
else{
cache[dom] = {};
cache[dom][eventName] = {};
cache[dom][eventName][name] = func;
}
},
remove:function(dom,eventName,name){
if(cache[dom] && cache[dom][eventName]){
cache[dom][eventName][name] = null;
}
}
};
}();
可以看到这里定义了3个方法,get、set、remove,就可以满足我们的需求了。
分享到:
相关推荐
分税制改革的前因后果.docx
施密特触发器你懂吗?怎么用运放构成一个简单的施密特触发器?该文档将会为你打开施密特触发器的认知大门
宏观专题报告:储蓄率下降的前因后果,如何看待我国储蓄率的变化-0307-海通证券-15页.pdf
超级兔子让浮动层消失的前因后果
商业智能(BI)的概念最早是由Gartner Group提出来的。确切地讲,商业智能并不是一项新技术,它是将数据仓库(DW)、联机分析处理(OLAP)、数据挖掘(DM)等技术与客户关系管理(CRM)结合起来应用于商业活动的实际过程当中,...
本研究调查了美国银行业智力资本效率的决定因素和后果。 我们发现,银行对不良时期的个人机构记忆会降低其智力资本效率。 我们还发现,智力资本效率限制了银行的冒险行为,并增强了其会计保守性。...
在本文中将具体分析一个 DB2 数据库联机备份期间创建索引被锁等待的实际案例,使读者能够了解这一很有可能经常发生的案例的前因后果,在各自的工作场景能够有效的避免该问题,同时还可以借鉴本文中采用的 DB2 锁等待...
因果推断是研究如何更加科学地识别变量间的因果关系及多期DID和事件研究法的数据和代码 客观事物普遍存在着内在的因果联系,人们只有弄清事物发展变化的前因后果,才能全面地、本质地认识事物。基干事物发展的这种...
这类调查研究报告一般是就某一地域或企业而开展的,通常设计方案到政冶,经济发展,文化艺术,人口数量,自然地理,历史时间等各个领域的基本情况,对调查对象的发展趋势转变,来龙去脉,前因后果来做比较详尽的交待...
知晓某一热点只是第一步,下一步我们需要了解事情的前因后果,乃至舆论态势。这时候,热点事件分析工具就派上用场了。 1、知微事见 知微事见是一个热点事件分析工具,除了可以自行搜索热点事件外,还提供“事件...
前7章分别介绍了设计方法概论,Verilog HDL的语法,行为建模,同步设计,异步设计,功能性单元,I2C Slave设计。第8章为微处理器设计,第9章为JPEG Encoder设计。这两章通过两个完整的设计实例,为读者详述了设计...
整理了一下关于mysql的前因后果,以及如何避免隐式提交
区块链概念简述 内容介绍 技术详情 36页看懂区块链的前因后果
简单介绍SD卡的前因后果及其一般结构、使用方法、使用环境。
本书从工程师的角度讲述淘宝这个超大规模互联网系统的成长历程,及其所有主动和被动的技术变革的前因后果。书中有幕后故事、产品经验、架构演进、技术启蒙,也有大牛成长、业内八卦、失败案例、励志故事。全书文风...
本书从工程师的角度讲述淘宝这个超大规模互联网系统的成长历程,及其所有主动和被动的技术变革的前因后果。书中有幕后故事、产品经验、架构演进、技术启蒙,也有大牛成长、业内八卦、失败案例、励志故事。全书文风...
本书从工程师的角度讲述淘宝这个超大规模互联网系统的成长历程,及其所有主动和被动的技术变革的前因后果。书中有幕后故事、产品经验、架构演进、技术启蒙,也有大牛成长、业内八卦、失败案例、励志故事。全书文风...