Javascript之自定义事件
js中常见的有很多事件,例如click
,dbclick
,mouseover
等等,这些大部分都是一些鼠标或者键盘事件,但是,这些事件只可以负责监听一些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('你好');
- 本博客所有文章除特别声明外,均可转载和分享,转载请注明出处!
- 本文地址:https://www.leevii.com/?p=1014