2020-9-16日:高级技巧:观察者模式 - 自定义事件 ;
- 一、自定义事件【 观察者模式 】 ; 背后的概念:创建一个管理事件的对象,让其他对象监听那些事件;
- 组成:
- 主体 : 负责发布事件 ;
- 观察者 :通过订阅这些事件来 观察该主体 ;
- 主要概念: 【 类比 Dom绑定事件,DOM元素便是主体,你的事件处理代码便是观察者;】
- 主体并不知道观察者的任何事情,也就是说它可以独自存在并正 常运作即使观察者不存在 ;
- ,观察者知道主体并能注册事件的回调函数(事件处理程序)。
- 示例 :
- EventTarget 类型;有一个单独的属性 handlers ,储存事件处理程序;
- addHandler(),用于注册给定类型事件的事件处理程序;
- fire(),用于触发一个事件 ;
- removeHandler(),用于注销某个事件类型的事件处理程序;
-
function EventTarget() { this.handlers = {}; } EventTarget.prototype = { constructor: EventTarget, addHandler: function (type, handler) { if (typeof this.handlers[type] == "undefined") { this.handlers[type] = []; } this.handlers[type].push(handler); }, fire: function (event) { if (!event.target) { event.target = this; } if (this.handlers[event.type] instanceof Array) { var handlers = this.handlers[event.type]; for (var i = 0, len = handlers.length; i < len; i++) { handlers[i](event); } } }, removeHandler: function (type, handler) { if (this.handlers[type] instanceof Array) { var handlers = this.handlers[type]; for (var i = 0, len = handlers.length; i < len; i++) { if (handlers[i] === handler) { break; } } handlers.splice(i, 1); } } };
- ( 1 ) : addHandler( ) 方法 ;
- 过程解析:
- 当调用该方法时,会进行 一次检查,看看 handlers 属性中是否已经存在一个针对该事件类型的数组;
- 如果没有,则创建一个新 的
- 然后使用 push()将该处理程序添加到数组的末尾
-
addHandler: function (type, handler) { if (typeof this.handlers[type] == "undefined") { this.handlers[type] = []; } this.handlers[type].push(handler); // 事件可以添加多个,类比DOm ; },
- 参数:
- 事件类型;
- 处理该事件的函数 ;
- ( 2 ) :fire( )方法 ;
- 过程解析:
- 先给 event 对象设置一个 target 属性,如果它尚未被指定的话 ;
- 然后它就 查找对应该事件类型的一组处理程序,调用各个函数,并给出 event 对象 ;
- 因为这些都是自定义事件, 所以 event 对象上还需要的额外信息由你自己决定 ;
-
fire: function (event) { if (!event.target) { event.target = this; } if (this.handlers[event.type] instanceof Array) { var handlers = this.handlers[event.type]; for (var i = 0, len = handlers.length; i < len; i++) { handlers[i](event); // 循环执行了,事件处理程序,可能是多个方法,进行多项操作 ; } } },
- 参数: 一个至少包含 type 属性的对象 ;
- ( 3 ):removeHandler( )方法 ;
- 过程解析 :
- addHandler()的辅助 ;
- 搜索事件处理程序的数组找到要删除的处理程序的位置 ;
- 找到了,则使用 break 操作符退出 for 循环 ;
- 然后使用 splice()方法将该项目从数组中删除 ;
-
removeHandler: function (type, handler) { if (this.handlers[type] instanceof Array) { var handlers = this.handlers[type]; for (var i = 0, len = handlers.length; i < len; i++) { if (handlers[i] === handler) { break; } } handlers.splice(i, 1); } }
- 参数: addHandler()的辅助,它们接受的参数一样 ;
- 事件的类型 ;
- 和事件处理 程序 ;
二、EventTarget 类型的自定义事件的调用 ;
-
function handleMessage(event) { alert("Message received: " + event.message); } //创建一个新对象 var target = new EventTarget(); //添加一个事件处理程序 target.addHandler("message", handleMessage); // 添加handleMessage事件方法; //触发事件 target.fire({ type: "message", message: "Hello world!"}); // { type: "message", message: "Hello world!"} 就是传递给事件处理程序 handleMessage(event)的参数 ;
//删除事件处理程序 target.removeHandler("message", handleMessage); //再次,应没有处理程序 target.fire({ type: "message", message: "Hello world!"});
三、继承 EventTarget 并获得上述行为 ;
- 示例:
-
function Person(name, age) { EventTarget.call(this); this.name = name; this.age = age; } inheritPrototype(Person, EventTarget); // 寄生组合继承 Person.prototype.say = function (message) { this.fire({ type: "message", message: message }); };
- 备注:
- Person 类型使用了寄生组合继承(参见第 6 章)方法来继承 EventTarget ;
- 调用了 say() 方法,便触发了事件,它包含了消息的细节 ;
- 某种类型的另外的方法中调用 fire()方法是很常见的, 同时它通常不是公开调用的 ;
- 使用:
// 定义:Person function Person(name, age) { EventTarget.call(this); this.name = name; this.age = age; } inheritPrototype(Person, EventTarget); // 寄生组合继承 Person.prototype.say = function (message) { this.fire({ type: "message", message: message }); };
// 使用 function handleMessage(event) { alert(event.target.name + " says: " + event.message); } var person = new Person("Nicholas", 29); //创建新 person person.addHandler("message", handleMessage); //添加一个事件处理程序 person.say("Hi there."); //在该对象上调用 1 个方法,它触发消息事件 // 不是公开调用 ,调用了一个别的方法触发;
为什么使用 :
- 代码中存在多个部分在特定时刻相互交互的情况下 ;
- 如果每个 对象都有对其他所有对象的引用,那么整个代码就会紧密耦合 ;
- 同时维护也变得很困难,因为对某个对 象的修改也会影响到其他对象 ;
使用效果:
- 自定义事件有助于解耦相关对象 ;
- 保持功能的隔绝 ;
- 很多情况中, 触发事件的代码和监听事件的代码是完全分离的 ;
Made by ---- Rise To The Heightest Then Qualitative Change

浙公网安备 33010602011771号