Home » Code » Javascript 自定义事件

Javascript 自定义事件

在Bootstrap中,一些组件预留了很多事件接口提供用户 。比如模态框显示出来后有shown.bs.modal事件,标签页有shown.bs.tab事件等,可以很方便的让我们在一些后续操作。而且在shown.bs.tab事件对象中,还有一个relatedTarget属性指向前一个tab,很实用。在感叹它的接口设计得很强大的同时不由想知道,它是如何实现的。

在Bootstrap使用的是jQuery,因此它这些事件接口也是在jQuery的基础上实现的。在jQuery中,只需要on()方法,即可以为对象添加自定义事件。学着Bootstrap的做法,来简易的模拟一下它模态框shown.bs.modal和hidden.bs.modal事件。

(function($) {
	var MODAL = function($elem) {
		this.elem = $elem;
		var _this = this;
		$elem.on('click', '.cancel', function() {
			_this.hide();
		});
	}
	MODAL.prototype.show = function() {
		this.elem.show().trigger({
			type: 'my.modal.show',
			testattr: 'test'
		});
	}
	MODAL.prototype.hide = function() {
		this.elem.hide().trigger({
			type: 'my.modal.hide',
			testattr: 'test'
		});
	}
	$.fn.modal = function(type) {
		var modal = this.data('my.modal');
		if (!modal) {
			this.data('my.modal', modal = new MODAL(this));
		}
		if (modal[type]) {
			modal[type]();
		}	
	}
})(jQuery);

在代码中,为jQuery添加了一个modal方法来操作模态框。在modal方法中,将MODAL对象使用jQuery的data方法存储到模态框jQuery对象中,而且还实现了类似“单例”的效果。在MODAL对象中,有控制模态框展示的show()方法和控制隐藏的方法hide(),在执行完对应操作后,触发相应的my.modal.show和my.modal.hide事件,使用的是jQuery中的trigger()方法,注意此时它的参数是json对象,type即是事件类型,要额外添加到事件对象中的的属性也是写到这里边,这里添加了一个testattr的属性,值为test。

这时,我们监听my.modal.show、my.modal.hide事件即可。

$modal = $('.my-modal');
$modal.on('my.modal.show', function(e) {
	console.log('my.modal.show-----done');
	console.log(e.testattr);
})
$modal.on('my.modal.hide', function(e) {
	console.log('my.modal.hide-----done');
	console.log(e.testattr);
})
$modal.modal('show');

页面加载后则显示模态框,点击取消按钮(.cancel)则隐藏。输出信息如下:

my.modal.show-----done
test
my.modal.hide-----done
test

以上是借助jQuery的强大功能来实现的。如果是纯粹的Javascript,如何实现这样的效果呢?

首先定义一个事件处理类,负责事件的添加、删除、触发。

(function() {
	var CEV = window.CEV = function() {
	}
	CEV.prototype = {
		constructor: CEV,
		__cev_handlers: {},
		addHandler: function(type, handler) {
			if (typeof handler !== 'function') {
				return;
			}
			if (!(type in this.__cev_handlers)) {
				this.__cev_handlers[type] = [];
			}
			this.__cev_handlers[type].push(handler);
		},
		removeHandler: function(type, handler) {
			if ((!(type in this.__cev_handlers)) || (typeof handler !== 'function')) {
				return;
			}
			var __cev_handlers = this.__cev_handlers[type];
			var len = __cev_handlers.length;
			for (var i = 0; i < len; i++) {
				if (__cev_handlers[i] === handler) {
					__cev_handlers.splice(i, 1);
					break;
				}
			}
		},
		triggerHandler: function(type) {
			if (!(type in this.__cev_handlers)) {
				return;
			}
			var __cev_handlers = this.__cev_handlers[type];
			var len = __cev_handlers.length;
			var args = Array.prototype.slice.call(arguments).splice(1);
			for (var i = 0; i < len; i++) {
				var func = __cev_handlers[i];
				func.apply(this, args);
			}
		}	
	}
	CEV.extend = function(obj) {
		var cev = new CEV();
		var props = Object.getOwnPropertyNames(cev.constructor.prototype).splice(1);
		for(var i in props) {
			obj[[props[i]]] = cev[props[i]];
		}

	}
})();

事件处理类全名为CEV,在它的原型上添加一个__cev_handlers属性存储所有类型的所有事件。还有一个静态方法extend(),用于给对象扩展属性方法。

对于模态框,它基本不变:

(function(window) {
	var MODAL = window.MODAL = function(elem) {
		this.elem = elem;
		var _this = this;
		elem.querySelector('.cancel').addEventListener('click', function() {
			_this.hide();
		}, false);
	}
	MODAL.prototype = {
		constructor: MODAL,
		show: function() {
			this.elem.style.display = "block";
		},
		hide: function() {
			this.elem.style.display = "none";
		}
	}
})(window);

如何使用CEV类为这个模态框类添加自定义事件呢?我们需要在show/hide方法中使用triggerHandler触发自定义事件。然而,要能使用add/remove/trigger这一套,就得往它的原型上扩展这些方法,CEV.extend()一下轻松解决。

添加自定义事件后的模态框类如下:

(function(window) {
	var MODAL = window.MODAL = function(elem) {
		this.elem = elem;
		var _this = this;
		elem.querySelector('.cancel').addEventListener('click', function() {
			_this.hide();
		}, false);
	}
	MODAL.prototype = {
		constructor: MODAL,
		show: function() {
			this.elem.style.display = "block";
			this.triggerHandler('my.modal.show', 'test');
		},
		hide: function() {
			this.elem.style.display = "none";
			this.triggerHandler('my.modal.hide', 'test');
		}
	}
	window.CEV.extend(MODAL.prototype);
})(window);

就添加了一行,模态框对象就拥有了CEV对象的全部功能,其实这就是所谓的复制继承。

var modalDom = document.querySelector('.my-modal');
var modal = new MODAL(modalDom);
modal.addHandler('my.modal.show', function(testattr) {
	console.log('my.modal.show');
	console.log(testattr);
});
modal.addHandler('my.modal.hide', function(testattr) {
	console.log('my.modal.hide');
	console.log(testattr);
});
modal.show();

以上代码,运行结果跟上边使用jQuery的是一样的。如果不在MODAL类中扩展CEV的功能,在对象中也是可以的,只是在show/hide时就无法触发自定义的事件了。但它依然有add/remove/trigger这一套。

Leave a Reply

Your email address will not be published. Required fields are marked *

*

Time limit is exhausted. Please reload CAPTCHA.