Javascript之自定义事件

js中常见的有很多事件,例如clickdbclickmouseover等等,这些大部分都是一些鼠标或者键盘事件,但是,这些事件只可以负责监听一些dom操作,如果是非dom呢,就可以使用自定义事件了。

实现一个EventUtil,它包括添加事件,触发事件和删除事件几个基本功能。在EventUtil的构造函数中初始化一个events对象用于保存事件类型与事件处理函数。

function EventUtil() {
    this.events = {};
}

首先是添加事件,可以参考dom的click事件来实现。第一个参数传入事件类型,第二个参数为处理函数。

add: function (type, fn) {
    if (!(this.events[type] instanceof Array)) {
        this.events[type] = [];
    }
    this.events[type].push(fn);
    return this;
}

如果当前实例中events[type]为一个非数组,说明该类型还没被添加,所以要初始化其为一个数组,然后将该事件类型所对应的处理函数添加到数组中保存。

紧接着是自定义函数的触发。通过传入事件类型,来触发对应的处理函数。

fire: function (type) {
    if (type && this.events[type]) {
        var args = Array.prototype.slice.call(arguments, 1);
        if (this.events[type] instanceof Array) {
            for (var i = 0, l = this.events[type].length; i < l; i++) {
                this.events[type][i].apply(this, args);
            }
        }
    }
    return this;
}

检测对应类型的函数处理对象数组是否存在,然后遍历这个数组获取每一个处理函数,然后触发这些函数,将其作用域绑定为当前EventUtil的实例对象。Array.prototype.slice.call(1)表示通过Event.fire传递的type参数之后的所有参数数组,将这些参数也传给对应处理函数的参数中去。

最后就是自定事件的删除处理了。可以通过传入事件类型和一个对象信息,这个对象信息可以是一个数组,包含要被移除的处理函数列表,也可以是一个函数,表示要被移除的处理函数,还可以不传值,如果不传值,表示该事件类型下的所有事件处理函数都要被移除。根据这个思路,可以如下实现:

remove: function (type, fn) {
    var events = this.events[type];
    if (events instanceof Array) {
        if (typeof fn === 'function') {
            for (var i = 0, l = events.length; i < l; i++) {
                if (fn === events[i]) {
                    events[i] = null;
                    events.splice(i, 1);
                    break;
                }
            }
        } else if (fn instanceof Array) {
            for (var fni = 0, fnl = fn.length; fni < fnl; fni++) {
                this.remove(type, fn[fni]);
            }
        } else {
            delete this.events[type];
        }
    }
}

那么,这样一个简单的事件自定义处理类就实现了。

在其它的类中继承EventUtil类,就可以使用其方法,继承的方法可以参考JavaScript继承最佳实践这篇文章。例如有个Person类,继承了EventUtil类,然后就可以事件自定处理方法了。

function Person(name) {
    EventUtil.call(this);
    this.name = name;
}

inheritPrototype(Person, EventUtil);

Person.prototype.sayMessage = function (message) {
    this.fire('message', message);
};

var p = new Person('张三');

p.add('message', function (message) {
    console.log(message);
});

p.sayMessage('你好');  //你好

这样有什么好处呢?使用自定义事件有助于解耦相关对象,保持功能的隔绝,在很多情况下,触发事件的代码和监听事件的代码是完全分离的。完整的代码如下:

function EventUtil() {
    this.events = {};
}

EventUtil.prototype = {
    constructor: this,
    add: function (type, fn) {
        if (!(this.events[type] instanceof Array)) {
            this.events[type] = [];
        }
        this.events[type].push(fn);
        return this;
    },
    fire: function (type) {
        if (type && this.events[type]) {
            var args = Array.prototype.slice.call(arguments, 1);
            if (this.events[type] instanceof Array) {
                for (var i = 0, l = this.events[type].length; i < l; i++) {
                    this.events[type][i].apply(this, args);
                }
            }
        }
        return this;
    },
    remove: function (type, fn) {
        var events = this.events[type];
        if (events instanceof Array) {
            if (typeof fn === 'function') {
                for (var i = 0, l = events.length; i < l; i++) {
                    if (fn === events[i]) {
                        events[i] = null;
                        events.splice(i, 1);
                        break;
                    }
                }
            } else if (fn instanceof Array) {
                for (var fni = 0, fnl = fn.length; fni < fnl; fni++) {
                    this.remove(type, fn[fni]);
                }
            } else {
                delete this.events[type];
            }
        }
    }
};

function inheritPrototype(subClass, superClass) {
    var prototype = Object(superClass.prototype);
    prototype.constructor = subClass;
    subClass.prototype = prototype;
}

function Person(name) {
    EventUtil.call(this);
    this.name = name;


}

inheritPrototype(Person, EventUtil);

Person.prototype.sayMessage = function (message) {
    this.fire('message', message);
};


var p = new Person('张三');

p.add('message', function (message) {
    console.log(message);
});

p.sayMessage('你好');
如果您觉得本文对您有用,欢迎捐赠或留言~
微信支付
支付宝

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注