Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
我们都知道,鼠标点击 click,触屏的 touch 等事件,可以触发相应的事件处理程序,也可以为这些事件添加事件处理程序,实际开发过程中可供我们使用的事件很少,click、doubleclick,mouseover、mousemove…. 等等这些。但当我们的程序越来越复杂的时候,光靠这些最底层的监听似乎已近不能满足我们的需求了。我们就需要我们自己去定义事件(其实就是我们写的函数),尤其是组件开发过程中,用的尤为多。
既然是事件,就要有事件的特性。我们要能为这个事件添加监听程序,这个事件触发时,监听程序也一定要触发才行。原理跟底层的事件类似。只不过,需要我们自己处理这些。
比如我们写了一个弹窗组件 Box,他有弹出显示的方法 show,还有关闭的方法 close 等。
可能有确定按钮、取消按钮等操作。随着产品或项目越复杂,被添加到这些确定或取消的操作也会越来越多。怎么办?一种是最原始的监听这些按钮的 click 事件,然后的写不同的回调。但是用回调的方式,有个弊端,当项目需求改变的时候,要往这个按钮上再另加个回调的时候,就要改原先的代码,要是以后再来一次,又要改。维护成本相当大。
我们不妨换个思路,把这个'确定'或'取消'想成像 click 这样的事件,当'确定'这个事件发生时其相应的一系列事件都会发生。就可以很好的解决这个问题。
基本原理:事件队列,即将监听程序存到一个数组中,再自定函数执行时,将添加监听数组中每个函数执行一遍。
定义一个对象专门用于存储自定义事件,定义一个方法用于注册监听,还有一个方法需要我们主动触发这个注册的监听程序 (因为不像 click 等事件可以被浏览器监听捕获,浏览器无法识别我们自己定义的东西)。
代码如下:
- //定义一个Box类
- function Box(){
- //other code
- this.handlers = {};//存储事件的对象
- }
- Box.prototype = {
- constructor: Box,
- //显示方法
- show: function (){
- //code
- //this.fire('show');
- },
- //关闭方法
- close: function (){
- //code
- //this.fire('close');
- },
- //监听方法,模拟addEventListener,其中type为事件函数,handler为需要触发的函数。
- addListener: function (type,handler){
- if (typeof this.handlers[type] == 'undefined')this.handlers[type] = [];
- this.handlers[type].push(handler);//将要触发的函数压入事件函数命名的数组中
- },
- //手动触发方法
- fire: function (type){
- if ( this.handlers[type] instanceof Array ){
- var handlers = this.handlers[type];
- //遍历事件函数监听的程序,依次执行
- for (var i=0;i<handlers.length;i++){
- handlers[i]();
- }
- }
- },
- //事件解绑
- removeListener: function (type,handler){
- if (!this.handlers[type]) return;
- var handlers = this.handlers[type];
- if (handler == undefined){
- handlers.length = 0;//不传某个具体函数时,解绑所有
- }else if( handlers.length ){
- for ( var i=0;i<handlers.length;i++ ){
- if ( handlers[i] == handler ){
- //解绑单个
- this.handlers[type].splice(i,1);
- }
- }
- }
- }
- }
剩下就是在需要的的时候添加注册监听了,比如
- var box = new Box();
- function listenShow1(){
- console.log(11);
- }
- function listenShow2(){
- console.log(22);
- }
- box.addListener('show',listenShow1);
- box.addListener('show',listenShow2);
- box.show();
当 show 方法执行,在外部或者 show 方法内部执行,这个可能根据实际具体项目或这具体情况来确定。
当然以上只是基本原理,可能没有特别考虑更为复杂或具体的实际情况。比如解绑是只想解绑某一类,像 jQuery 那样,在事件身上加命名空间,解绑该命名空间上的所有函数。但是自定义事件的基本原理就是如上描绘的那样!
来源: http://www.phperz.com/article/17/0322/326585.html