浏览器内置了一些javascript的方法,比如说click, mouseover, mousein ... 可以在用户进行了一些浏览器内置的默认行为(点击,鼠标滑过DOM)的时候会触发。
说道自定义javascript事件,给大家印象比较深的也许是jQuery的bind方法,可以添加一些用户自定义的事件,再用trigger的方法来触发之。
基本的实现代码如下:
/**
* 事件管理组件
* 版权所有(C) 2013 EchoFUN (xukai.ken@gmail.com)
*
* 2013.12.12 初始化文件。
*
* Example:
* var test = document.getElementById('test');
* evt(test).bind('custom', function() {
*
* })
*
* evt(test).trigger('custom');
*
*/
;var cacheId = 'cache' + setTimeout(function() {}, 0);
var evt = (function(global, cacheId) {
'use strict';
var isIE = !!document.attachEvent;
var typeExpress = /^[a-z]+$/i;
// 缓存所有的事件。
var events = {};
// 产生一个唯一的键值。
var globalId = 1;
function wrap(node) {
return new _wrap(node);
}
function _wrap(node) {
var _node = (node && node.nodeType == 1) ? node : '';
if (!_node) {
return 'Invalidate node !';
}
_node[cacheId] || (_node[cacheId] = globalId++);
this._node = _node;
}
function _type(o) {
var type = {}.toString.call(o);
return type.slice(8, -1).toLowerCase();
}
var proto = _wrap.prototype;
proto.bind = function(type, handle, capture) {
if (_type(type) !== 'string'
|| !typeExpress.test(type)
|| _type(handle) !== 'function') {
return 'Invalidate params !';
}
var node = this._node;
if (isIE) {
node.attachEvent('on' + type, handle);
} else {
node.addEventListener(type, handle, capture);
}
// 如果还未开始对这个对象有缓存,则加入缓存序列。
if (!events[node[cacheId]]) {
events[node[cacheId]] = {};
}
var evts = events[node[cacheId]];
if (evts && evts[type]) {
evts[type].push(handle);
} else {
evts[type] = [handle];
}
return this;
};
proto.unbind = function(type, handle, capture) {
if (_type(type) !== 'string'
|| !typeExpress.test(type)
|| (handle && (_type(handle) !== 'function'))) {
return 'Invalidate params !';
}
var node = this._node;
var evts = events[node[cacheId]];
if (!evts[type]) {
return 'Not exist specified event !';
}
if (isIE) {
node.detachEvent('on' + type, handle);
} else {
node.removeEventListener(type, handle, capture || false);
}
if (handle) {
for (var i = 0; i < evts[type].length; i++) {
if (evts[type][i] == handle) {
evts[type].splice(i, 1);
}
}
} else {
evts[type] = [];
}
return this;
};
proto.trigger = function(type) {
if (_type(type) !== 'string') {
return 'Invalidate params !';
}
var args = Array.prototype.slice.call(arguments);
args.shift();
var evts = events[this._node[cacheId]];
if (evts[type]) {
var evtsList = evts[type];
for (var i in evtsList) {
evtsList[i].apply(this._node, args);
}
}
return this;
};
return wrap;
})(this, cacheId);
完整示例请移步Github event.js文件
对javascript的事件自定义,只是其庞大事件系统的冰山一角。
口水横飞的讲了这么多,不知道你会不会有这样的疑问。
自定的这些事件有个蛋用啊!?
网上关于自定义事件的方法一抓能有一把,但是总结为何这样做的文章却很少。
具我在项目中使用情况看来,可以总结出起码有如下两种情形:
a). 在制作一些前端组件的时候,可以为特定的事件添加钩子
举个栗子:
人人网的表情组件(PS. 居然注释部分没有压缩掉哈,剩下了我的口水了。)
开发人员可以对new了XN.ui.emoticons这么个对象后的返回值添加各种事件。组件中已经在各个关键节点(渲染结构,绑定事件,展示)的地方fireEvent了这些事件。
这样就可以进行无侵入式的编程。在不改变原有逻辑的情况下,添加一些自己想要的行为,岂不爽哉!?
b). 模块化开发中,可以方面的为各个模块之间进行解耦
现在的前端工程里,有追求的前端们(咳咳,你懂的!)大多使用了common.js的规范来组织前端代码,各个模块的数据和操作都可能是独立的,但是模块和模块之间的沟通通过什么方式来进行呢?
(自定义事件!)
恭喜,都会抢答了。
细细说来,有点类似于前些文章中聊到的观察者模式,在我发布了一篇微博的时候,需要出发右侧的微博数目。这个时候,我就可以在发布框的模块中,trigger或者是fireEvent一下事先已经绑定在右侧数目计数器上的一个自定义的事件,这个举例比较简单,如果模块功能很复杂,就能做到充分的解耦。
能力有限,欢迎各路大神继续补充和拍砖。
写在结尾处:
之前的文章里很少有提及CSS的部分,之所以不涉及这块,并非不是很了解。奈何没有像@张鑫旭单口相声般的牛逼技能,写出来的文章就像懒婆娘的裹脚布一样。这个也是需要我学习和将强的地方啦,哈哈。
Enjoy it !
转载请注明出处
botobe.net
本文Github链接
2013.12.13
最近情绪不佳,有点小郁闷!
依旧Merci !