浏览器内置了一些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 !