简体   繁体   English

如何在角度应用程序上收听外部js事件?

[英]How to listen to an external js event on angular app?

I have a external js library on my angular app, I added it as a global script on the angular-cli.json scripts array. 我的角度应用程序上有一个外部js库,我在angular-cli.json脚本数组中添加了它作为全局脚本。 Its working fine, but I need to assign some functions as response to events of this library. 它的工作正常,但我需要指定一些函数作为对这个库的事件的响应。 This library has an Display object wich has some events: 这个库有一个Display对象,它有一些事件:

Display.onplay
Display.onpause

How can I listen to these events in my angular component.ts ? 我怎样才能在我的角度组件中听这些事件。

In plain javascript web application is just assign it to a function like: 在普通的javascript Web应用程序只是将它分配给一个函数,如:

  Display.onplay = function () { console.log('play'); }

But on angular i have no idea if its possible to do it. 但在角度上,我不知道它是否有可能做到这一点。

It is possible and appropriate to access external Javascript libraries from an Angular application. 从Angular应用程序访问外部Javascript库是可能的,也是适当的。 There are some issues to keep in mind however. 但是要记住一些问题。

Type Declarations 键入声明

I will get some compilation errors if I type just like that in typescript. 如果我在打字稿中打字,我会得到一些编译错误。

This is common in Typescript. 这在Typescript中很常见。 There are a couple of ways to fix this issue. 有几种方法可以解决这个问题。

The first (and likely best) approach is to include a Typescript type declaration (.d.ts) file for the Display library in your project. 第一种(也可能是最好的)方法是为项目中的Display库包含Typescript类型声明(.d.ts)文件。 If this is a popular third-party library it may already be available as an npm package called @types/[PACKAGE_NAME]. 如果这是一个受欢迎的第三方库,它可能已经作为名为@ types / [PACKAGE_NAME]的npm包提供。 If it is not available you can write a type declaration. 如果它不可用,您可以编写类型声明。 More information about creating and including type declarations can be found in the Typescript Documentation . 有关创建和包含类型声明的更多信息,请参见Typescript文档

The second approach is to simply use (Display as any).onplay or (Display as any).onpause to avoid compilation errors. 第二种方法是简单地使用(Display as any).onplay(Display as any).onpause避免编译错误。

Unit Testing 单元测试

Placing this code in your top-level component may suffice for your needs, but I doubt it. 将此代码放在顶级组件中可能足以满足您的需求,但我对此表示怀疑。 This restricts where the Display library can be used. 这限制了可以使用Display库的位置。

I suggest wrapping the library in a well designed service. 我建议将图书馆包装在精心设计的服务中。 Using a service allows the Display library to be accessed by multiple components/services. 使用服务允许多个组件/服务访问Display库。

You may be unit testing the code that relies on the Display library. 您可能会对依赖于Display库的代码进行单元测试。 If this is the case the appropriate place to use (Display as any).onplay = ... would definitely be in a service. 如果是这种情况,适当的使用场所(Display as any).onplay = ...肯定会在服务中。 Services make it easier to stub the functionality of the third-party libraries. 服务可以更容易地保留第三方库的功能。

Here's an untested example service: 这是一个未经测试的示例服务:

import { Injectable } from '@angular/core';

export interface IDisplayService {
    onPlay(callback: () => void): void;
    onPause(callback: () => void): void;
}

@Injectable()
export class DisplayService implements IDisplayService {
    private onPlayCallback: () => void;
    private onPauseCallback: () => void;

    constructor() {
        if (!Display) {
            throw new Error('Display library is required');
        }

        (Display as any).onplay = () => {
            if (this.onPlayCallback) { this.onPlayCallback(); }
        };
        (Display as any).onpause = () => {
            if (this.onPauseCallback) { this.onPauseCallback(); }
        };
    }

    // Using a function allows you to register multiple callbacks
    // if you choose to allow it later on.
    onPlay(callback: () => void): void {
        this.onPlayCallback = callback;
    }

    onPause(callback: () => void): void {
        this.onPauseCallback = callback;
    }
}

Another aproach using a service and observable of the service an code in your app.component 另一个aproach使用服务和可观察的服务和app.component中的代码

app.component app.component

declare var Display:any //<--declare the variable
@component(..)

export class AppComponent {
  constructor(private outEventService:OutEventService) {
  }
  Display.onplay (){   //the function like javascript only call function of service
     this.outEventService.sendEvent("play");
  }
  Display.onpause (){
     this.outEventService.sendEvent("pause");
  }
}

outEventService outEventService

export class OutEventService{

    private listeningSource:Subject<any>=new Subject<any>();
    displayEvent:Observable<any>=this.listeningSource.asObservable();

    constructor() {
    }

    sendEvent(evento:any)  //Simply make a change in the observable
    {
        this.listeningSource.next(evento);
    }
}

A component that subscribe event 订阅事件的组件

constructor(private ngZone: NgZone,
    private outEventService: outEventService) {
  }
ngOnInit() {
this.outEventService.displayEvent.subscribe((evento: any) => {
      if (evento == "pause") {  
           do something
      }
      if (evento == "other") {  //Sometimes you must use ngZone to angular take account the change
        this.ngZone.run(() => {
            do something 
        })
      }
    });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM