事件的前因后果(2)

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,就可以满足我们的需求了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值