Angular 6 - 在不相关的组件之间共享一个对象

标签 angular rxjs communication phaser-framework angular-components

任务:

我正在将一个现有的 HTML5 项目(一个基于 Phaser 的科学软件)集成到 Angular 中,目的是更好地构建不断扩展的 UI。

该软件位于其自身的组件中并且正在运行。该软件的所有功能都从一个 Controller 类中公开。我在 Phaser 项目的状态中有一个 Controller 类的实例。

想象一个新组件(例如,顶级菜单)我希望能够说:

<div (click)="this.controller.makeAction()"></div>

,其中“this.controller”是一个实例,保存在顶级菜单组件中。

相关研究:

我在很多地方都读到过,在不相关的组件之间进行通信的推荐方法是通过服务和使用 rxjs BehaviorSubject。好的...问题来了:

问题:

当我创建服务时,我必须设置 BehaviorSubject 的实例。问题是我不知道游戏什么时候准备好,以便访问状态,从而为服务提供 Controller 。所以.. BehaviorSubject 保持为空,我得到一个错误。

我真的很想避免将 Angular 代码放在 Phaser 项目中,因为它们应该尽可能保持分离(目前没有任何耦合)。

问题:

我的方法正确吗? Controller 将提供给任何 UI 元素,从而提供给任何组件。如何解决这个问题?

相关代码:

<强>1。服务

// Omitting imports and decorators
export class UserActionControllerService {
  private _userActionController = new BehaviorSubject<UserActionController>(null);
  userActionController = this._userActionController.asObservable();
  constructor() {  }
  setUAC(userActionController: UserActionController){
    this._userActionController.next(userActionController);
  }
}

<强>2。使用顶部菜单中的服务

//Omitting imports and decorator
export class TopMenuComponent implements OnInit {
  userActionController: UserActionController;
  constructor(private uac: UserActionControllerService) {  }
  ngOnInit() {
    this.uac.userActionController.subscribe((value) => {
      this.userActionController = value;
    });
  }

和 html...

<p>{{this.userActionController | async | json}}</p>

<强>3。在服务中设置 Controller 的值

//Ommitting imports and decorator
export class GteCoreComponent implements OnInit {
  game: Phaser.Game;
  constructor(private userActionControllerService: UserActionControllerService) {}
  ngOnInit() {
    this.game = new GTE(width, height);
this.userActionControllerService.setUAC(this.game.state.states.MainScene.userActionController);
  }
}

最后一行会产生错误,因为游戏还没有创建。我试过 setTimeout() ,还是没有用。

提前感谢您的帮助!

编辑:

我设法让它与 setTimeout 一起工作,这看起来像是一个 hack。还有其他建议吗?

编辑 2:

根据要求,这是 GTE 类:

export class GTE extends Phaser.Game {
  game: Phaser.Game;    
  constructor(width?: number, height?: number) {    
    super(width, height, Phaser.CANVAS, 'phaser-div', null, false, true);    
    this.game = this;
    this.game.state.add('Boot', Boot, false);
    this.game.state.add('MainScene', MainScene, false);
    this.game.state.start('Boot');
  }
}

最佳答案

正如您所注意到的,您已经使用 setTimeout 解决了问题,这表明导致您的问题的是时间问题。

setTimeout 做了两件事:

首先,它将回调的处理延迟一些指定的毫秒数。这可能会有问题,因为如果用户的浏览器有点慢/更忙,您正在等待的东西准备就绪可能需要超过指定的时间。最好在事件后触发这样的事件,而不是等待时间 - 如果您等待足够长的时间以确保它准备就绪,那么对于大多数用户来说,您等待的时间将比必要的时间长得多。

setTimeout 做的第二件事是将回调的执行推送到下一个 JS 执行帧。这在某些情况下可能是必需的,因为它允许其他排队的工作在继续之前完成。即使您将超时设置为 0 毫秒,这也会起作用 - 如果这解决了问题,那么 setTimeout 可以安全地用于这种情况。

尽管如此,即使您处于这些场景中的第二种情况,结束事件也会更加清晰 - 并且某人或您 future 的自己不太可能出现并在以后取消它!

查看 Phaser.Game documentation有一个 isBooted 标志,因此如果没有暴露事件,您可以在 GTE 类中创建一个:

export class GTE extends Phaser.Game {
  game: Phaser.Game; 
  private readyCallback: () => null;
  constructor(width?: number, height?: number, ready: () => null) {    
    super(width, height, Phaser.CANVAS, 'phaser-div', null, false, true);    
    this.game = this;
    this.game.state.add('Boot', Boot, false);
    this.game.state.add('MainScene', MainScene, false);
    this.game.state.start('Boot');
    this.readyCallback = ready;
    setTimeout(() => this.checkReady(), 100);
  }

  checkReady() {
    if (this.game.isBooted) this.readyCallback();
    else setTimeout(() => this.checkReady(), 100);
  }
}

关于Angular 6 - 在不相关的组件之间共享一个对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52059846/

相关文章:

angular - rxjs 中的 finally 和 finalize 有什么区别

Angular 2 : How do validate placeholder based on boolean condition

angular - 为什么在使用 ngrx 效果时会收到此可观察到的警告

communication - 您如何在小型开发团队中进行有效沟通?

unit-testing - 单元测试 Angular 2 authGuard; spy 方法没有被调用

javascript - 运行时Angular 2 Webpack环境配置

javascript - NGRX Effect withLatestFrom Typescript 错误 ts2345 故障排除

Angular 6 rxjs 管道不返回数据

grails - Grails Mail Plugin无法安装-尝试在Config中修复,但仍然无法正常工作

java - 如何在不使用调制解调器或接入点的情况下在 WIFI 下在 java(PC) 和 android 之间进行通信?