目前我有以下结构,一个对象 WebsocketService
和多个 FrontendController
。
WebsocketService
监听 websocket (duh) 并更新内部应用程序状态。这意味着在某些情况下,前端必须使用新值进行更新。
为了让我的 UI 代码和应用程序逻辑很好地分离,我设想了一种设计,其中 FrontendController
可以订阅 WebsocketService
发出的事件,很可能稍后还有其他服务.
我已阅读 Creating and triggering events on MDN 的文档.但所有这些都是以 DOM 为中心的。我的 WebsocketService
显然没有 addEventListener
函数。
我宁愿不使用第 3 方库。我想到的一个 hack 就是在某个地方有一个 id="events"
DOM 节点并让每个人都订阅它。然后 dispatchEvent
在该元素上,并让 FrontendController
决定他们关心。
当然我也可以为所有这些实现我自己的基础设施,但我也宁愿避免那样做,因为我很懒。
执行此操作的干净方法是什么?或者是否有更好的解决方案来分离我的应用程序逻辑和普通旧 javascript 中的前端?
最佳答案
我认为最简单的可能性是:
让您的 WebsocketService 扩展 HTMLElement
优点:
- 简单
- 您继承与事件相关的方法,包括 addEventListener 和 dispatchEvent。
缺点:
- 您继承了您永远不会使用的所有 DOM 方法和属性。
- 部分支持(FireFox 需要简单但特定的配置才能运行,Edge/Explorer 不支持)
示例:
//add some event
let piggyEvent = document.createEvent('Event');
piggyEvent.initEvent('piggy', true, true);
class WebSocketService extends HTMLElement {
constructor() {
super();
}
onDataArrival() {
//some code here...
}
onConnectionLoss() {
//some code here...
}
onHappyPiggyArrival() {
this.dispatchEvent(piggyEvent);
}
}
class FrontEndService {
constructor(socketService) {
this.socketService = socketService;
}
subscribe() {
this.socketService.addEventListener('piggy', (event) => {
alert("A new piggy has arrived, do something with it!");
})
}
}
//You must declare the new element
customElements.define('websocket-service', WebSocketService);
//Now let's try it
let socService = new WebSocketService(),
frontService = new FrontEndService(socService);
frontService.subscribe();
//nothing happens until...
socService.onHappyPiggyArrival();
- 实现自己的 addEventListener 方法并使用现有机制
- 实现您自己的精简事件机制
//add some event
let piggyEvent = document.createEvent('Event');
piggyEvent.initEvent('piggy', true, true);
class EventSupportedElement {
constructor() {
this.eventRegsitry = new Map();
}
_initRegEntry(entryName) {
if (!this.eventRegsitry.has(entryName)) {
this.eventRegsitry.set(entryName, []);
}
return this.eventRegsitry.get(entryName);
}
addEventListener(eventName, callback) {
this._initRegEntry(eventName).push(callback);
}
removeEventListener(eventName, callback) {
let eventNameCallbacks = this.eventRegsitry.get(eventName);
if (eventNameCallbacks && eventNameCallbacks.indexOf(callback) !== -1) {
eventNameCallbacks.splice(eventNameCallbacks.indexOf(callback), 1);
}
}
dispatchEvent(eventObject) {
if (eventObject.type && this.eventRegsitry.get(eventObject.type)) {
this.eventRegsitry.get(eventObject.type).forEach((callback) => {
//add any data to the event / use custom event and trigger
callback(eventObject);
});
}
}
}
class WebSocketService extends EventSupportedElement {
onDataArrival() {
//some code here...
}
onConnectionLoss() {
//some code here...
}
onHappyPiggyArrival() {
this.dispatchEvent(piggyEvent);
}
}
class FrontEndService {
constructor(socketService) {
this.socketService = socketService;
}
subscribe(eventName, callback) {
this.socketService.addEventListener(eventName, callback);
}
unsubscribe(eventName, callback) {
this.socketService.removeEventListener(eventName, callback);
};
}
//Now let's try it
let socService = new WebSocketService(),
frontService = new FrontEndService(socService),
onPiggyFn = (event) => {
alert("A new piggy has arrived, do something with it!");
};
frontService.subscribe('piggy', onPiggyFn);
//nothing happens until...
socService.onHappyPiggyArrival();
//now unsubscribe
frontService.unsubscribe('piggy', onPiggyFn);
//nothing happens...
socService.onHappyPiggyArrival();
无论选择哪一个,您都必须声明自己的自定义事件。
关于javascript - DOM 之外的浏览器 Javascript 中的自定义事件发射器/消费者,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51110935/