如何在JavaScript中使用自定义事件

jopen 12年前

JavaScript 的事件处理是所有浏览器端程序的基本必备技巧。当目标元素的事件被触发时,比如按钮被点击,鼠标移动,或者是表单提交,这些事件触发时都可以触发对应的方法。当然这个过程中我们可以传递一些参数过去来自定义很多事情。


一个要注意避免的就是事件与DOM元素的紧耦合。比如先看看下面这个代码,考虑到用一个简单表单来接受用户输入的信息。
<form id="msgbox" action="#" method="get">  <label for="msg">your message</label>  <input id="msg" value="" />  <button>SEND</button>  </form>


我们能写一段代码让屏幕上显示刚才表单提交的信息
document.getElementById("msgbox").addEventListener("submit", function(e) {   e.preventDefault();   var msg = e.currentTarget.getElementById("msg").value.trim();   if (msg) {    alert(msg);   }  }, false);


那么如果我们想对显示出来的这句话做一些操作,比如发一条tweet,或存储在服务器或者干些其他什么?则有两个选择:
1,对已有的事件处理方法添加代码
   这个方案的缺陷就是每当打算测试或者更新后来添加的事件处理方法时变得非常不弹性化,每当更改或者删除一些功能的时候,总会有一大段代码要跟着去修改。

2,为每一个功能都创建事件处理方法
   第二个方法很好的解决了前面方法的问题,虽然这个方法可能会一开始麻烦点。毕竟所有的方法代码都要处理重复的消息提取以及验证步骤。

设想假如能够自行触发自定义的"newMessage"事件而无需验证是否有message提交,或假如能监控整个HTML文档或者body这样的标签而不仅仅只是某个表单的节点,能否做到呢?这就是自定义事件要解决的问题了。

自行触发一个自定义事件是很简单的;如下代码就是传递一个name,details以及options到新建的 CustomEvent对象中:
var event = new CustomEvent(   "newMessage",   {    detail: {     message: "Hello World!",     time: new Date(),    },    bubbles: true,    cancelable: true   }  );



这个案例中,"newMessage"是一个自定义事件类型。而第二个参数包含了此对象的三个属性(detail,bubbles,cancelable)。

detail: 包含了自定义事件的具体信息,这里仅仅就包括了一个message与一个time
bubbles: 如果是true,则事件会一直传递给自身的父对象元素,接着父对象也会触发此类事件
cancelable: 如果是true, 事件可以被事件触发元素的 stopPropagation( ) 方法停止

现在,我们需要针对某个特定元素来触发此类事件。
document.getElementById("msgbox").dispatchEvent(event);


可以用以下代码订阅这个事件的处理。
document.addEventListener("newMessage", newMessageHandler, false);


展示页
查看自定义事件的展示页
一个标准的事件处理方法将会查看提交到HTML表单的所有信息。下面这个方法先获取当前的消息,假设它已经被验证,最后自行触发一个新的"newMessage"的事件。
var msgbox = document.getElementById("msgbox");  msgbox.addEventListener("submit", SendMessage, false);  // new message: raise newMessage event  function SendMessage(e) {   e.preventDefault();   var msg = document.getElementById("msg").value.trim();   if (msg && window.CustomEvent) {    var event = new CustomEvent("newMessage", {     detail: {      message: msg,      time: new Date(),     },     bubbles: true,     cancelable: true    });    e.currentTarget.dispatchEvent(event);   }  }


所有的事件处理方法都可以订阅来处理那个 newMessage 事件。
// listen for newMessage event  document.addEventListener("newMessage", newMessageHandler, false);  // newMessage event handler  function newMessageHandler(e) {   LogEvent(    "Event subscriber on "+e.currentTarget.nodeName+", "    +e.detail.time.toLocaleString()+": "+e.detail.message   );  }


浏览器能力
不过上面这个 CustomEvent对象只有在 Chrome, FireFox以及Opera才能正常使用。而下一个版本的Safari也支持了。IE9以及更低版本暂时是不支持的。