JavaScript 自定义事件(一)

所谓自定义事件,就是有别于带有浏览器特定行为的事件(鼠标事件,键盘事件,html事件等),事件名称可以自定义,可以通过特定的方法进行添加,触发以及删除。自定义事件相当于是 观察者模式 ,可以把复杂逻辑解耦,代码可以写的很清晰,而且很容易复用。

一.JS事件应用初印象

我觉得更为准确的说,下面列举的是Dom事件的应用。我们在这里可以通过了解JS关于Dom事件的绑定,触发,解绑来一步一步书写我们自己的JS自定义事件。关于自定义事件,我决定分两步讲解。第一步,也就是这篇文章将要提到的循序渐进的一步一步完善自定义JS事件。第二步,我们封装一个与Dom元素有关的自定义事件函数。

// 事件绑定
function addEvent(element, eType, handler, bol) {
    if(element.addEventListener){           //如果支持addEventListener
        element.addEventListener(eType, handler bol);
    }else if(element.attachEvent){          //如果支持attachEvent
        element.attachEvent("on"+eType, handler);
    }else{                                  //否则使用兼容的onclick绑定
        element["on"+eType] = handle;
    }
}
// 事件解绑
function removeEvent(element, eType, handler, bol) {
    if(element.addEventListener){
        element.removeEventListener(eType, handler, bol);
    }else if(element.attachEvent){
        element.detachEvent("on"+eType, handler);
    }else{
        element["on"+eType] = null;
    }
}
//实例应用
var patty=document.getElementById("patty");
var sayHello=function (){
   alert("Hello!!!");
}
addEvent(patty,click,sayHello,false); //添加点击事件

这里我们关注下click事件的实现。我们可以很清楚的将其分成三部分:添加,触发,删除。
同时,我们必须考虑一个问题:事件和其处理函数应该怎样存储。事件分为很多种,click, mouseover, submit, keydown等等,每一种事件下又可以添加处理函数。这种一对多的映射关系,我们可以很自然想到用下面这样数据结构来存储事件。

_listener = {
"click": [func1, func2],
"custom": [func3],
...
}

二.自定义我们自己的JS事件

1.函数式实现
var _listener = {};   //存储事件和其处理函数
var addEvent = function(type, fn) {
      //添加
};
var fireEvent = function(type) {
     //触发
};
var removeEvent = function(type, fn) {
     //删除
};

//添加eat事件
addEvent("eat",function(){
  alert("eat an apple!");
})
// 触发自定义eat事件
fireEvent(eat);

我们没有详细展示函数式实现的代码,是因为这种写法较为基础且过多地暴露全局变量,我们稍微了解即可,具体函数地实现,我们在下面的方式会实现。

2.用字面量方式实现
var Event = {
    _listeners: {},    
    // 添加
    addEvent: function(type, fn) {
        if (typeof this._listeners[type] === "undefined") {
            this._listeners[type] = [];
        }
        if (typeof fn === "function") {
            this._listeners[type].push(fn);
        }    
        return this;
    },
    // 触发
    fireEvent: function(type) {
        var arrayEvent = this._listeners[type];
        if (arrayEvent instanceof Array) {
            for (var i=0, length=arrayEvent.length; i

字面量实现虽然减少了全局变量,但是其属性方法等都是暴露而且都是唯一的,一旦某个关键属性(如_listeners)不小心在某事件处reset了,则整个全局的自定义事件都会崩溃。因此,我们可以进一步改进,例如,使用原型链继承,让继承的属性(如_listeners)即使出问题也不会影响全局。

3.原型模式实现
var EventTarget = function() {
    this._listener = {};
};

EventTarget.prototype = {
    constructor:EventTarget,
    addEvent: function(type, fn) {
        if (typeof type === "string" && typeof fn === "function") {
            if (typeof this._listener[type] === "undefined") {
                this._listener[type] = [fn];
            } else {
                this._listener[type].push(fn);    
            }
        }
        return this;
    },
    addEvents: function(obj) {
        obj = typeof obj === "object"? obj : {};
        var type;
        for (type in obj) {
            if ( type && typeof obj[type] === "function") {
                this.addEvent(type, obj[type]);    
            }
        }
        return this;
    },
    fireEvent: function(type) {
        if (type && this._listener[type]) {
            var events = {
                type: type,
                target: this    
            };
            
            for (var length = this._listener[type].length, start=0; start

这样我们发现,event1和event2在共享方法的同时,又有自己的_listener 属性,彼此之间不会污染。

我相信大家通过上面的了解,对JS自定义事件一定有更深的理解了,OK这次就先讲这么多,谢谢观看!

你可能感兴趣的:(JavaScript 自定义事件(一))