【问题标题】:Plain Javascript as Angular 2 service纯 Javascript 作为 Angular 2 服务
【发布时间】:2017-07-03 07:07:42
【问题描述】:

我需要在 Angular 2 组件中添加托管的第三方 JavaScript 文件。每当在相关的第三方供应商专有系统中进行更改时,此文件都会更新,因此我不能简单地下载副本,将其包含在本地,然后将其导入项目中。

通常我会将此文件包含在脚本标记的顶层,然后只需使用declare <windowvar>: any 即可访问它。但是在这种情况下,由于组件本身正在尝试加载脚本,因此我无法声明 window 变量,因为在加载组件时它不存在于 window 对象上,这会产生错误。

我可以通过手动添加脚本标签来加载脚本,这很有效,但是我需要访问它创建的窗口变量才能正确使用它。而且我不能简单地使用间隔来查找它,因为打字稿会抛出 <windowvariable> does not exist on object window 的拟合。

我有什么方法可以 1) 在组件中加载托管的 JavaScript 文件,以及 2) 访问由加载的 JavaScript 文件创建的窗口变量?

【问题讨论】:

    标签: javascript angular typescript angular2-services


    【解决方案1】:

    实际上,您正在尝试从 CDN 获取“全局模块”javascript 库。 (我假设第 3 方库不是 CommonJS、AMD、UMD 或其他模块格式,因为它是通过唯一的全局变量访问的。)

    那么第一个问题是对应的 .d.ts 文件在哪里?它包含通知 Typescript 库的“形状”的名称和接口,以及声明全局变量将存在。如果您的第 3 方不提供,您需要自己编写。它不仅包含全局变量的声明,例如

    declare var theGlobalVarInQuestion: IInterfaceOfStuffInsideLibrary;

    还要声明接口,以及它的属性和它们的类型,一路向下。像这样:https://github.com/catamphetamine/libphonenumber-js/blob/master/index.d.ts

    您可以将 .d.ts 文件包含在 /node_modules/@types/nameOfSaidLibrary 中,但您需要将其签入您的源代码库(可能包含 .gitignore 体操),尤其是因为 npm prune 将删除它。或者,如果您将其放在其他位置,请修改 tsconfig.json typeroots 属性以查看该位置以及通常的 /node_modules/@types/ 文件夹。

    为了清楚起见,.d.ts 文件并没有(也不应该)实际创建变量;它只是声明它将在那里,因此 Typescript 编译器不会抱怨。它在运行时是否存在取决于您加载 js 的方式。

    如果您不是通过 index.html 中的脚本标记加载它,那么使用组件中的 Typescript import 语句可以这样做(给定 SystemJS 的正确配置或您正在使用的任何内容)或消费组件可以动态创建新的脚本标签并将其附加到 index.html。只需确保您的模块加载器没有尝试下载并在构建时立即将其与应用程序的其余部分捆绑在一起。听起来您希望每次在运行时都重新下载该库。

    【讨论】:

      【解决方案2】:

      更新 1:基于 cmets,以前的解决方案对您没有帮助。

      您可以通过在 Angular2 中使用 OpaqueToken 来做到这一点

      1。在单独的 ts 文件中创建一个用于查找实例的 Token,如下所示。

      import { OpaqueToken } from '@angular/core'
      
      export let name_of_The_Token = new OpaqueToken('name_Of_The_Window_Object');
      

      2. 在您的 App.module 中,您需要导入并声明一个变量,该变量是您的窗口对象的名称,它使Token 作为 angular2 服务,以便您可以跨组件使用该 javascript 文件中的属性、方法。

      import { name_of_The_Token } from '/* file_Path */';
      declare let name_Of_The_Window_Object : any;  //below your import statements
      

      第 3 步:注入到模块的 providers 数组中。

      { provide : name_of_The_Token , useValue : name_Of_The_Window_Object }
      

      在组件中使用此令牌的指南

      1. 像任何其他服务一样导入令牌并从 angular-core 中 @Inject

         import { name_of_The_Token } from '/* file_Path */';
         import { Inject } from '@angular/core';
        
      2. 在组件的构造函数中

         constructor(@Inject( name_of_The_Token ) private _serviceObject : any )       
        
      3. 在组件中的任何位置,您都可以将 javascript 文件的变量和方法用作

         this._serviceObject.method1()
         this._serviceObject.variable1
         .....
        

      注意:一个缺点是您将无法获得智能感知

      克服它: 如果您正在寻找智能感知,您需要将方法和变量包装在接口中,并在令牌的类型**(而不是任何)** 中使用它作为

      export interface myCustom {
            method1(args): return_Type;
            method2(args): void;
            .....
         }
      

      LIVE DEMO ToasterService

      【讨论】:

      • 这绝不是一个包依赖,它是一个第三方资源,必须从他们提供的 URL 从他们的服务器加载。
      • 它只是一个javascript还是一个功能很少的模块??
      • 它只是一个 javascript 文件,它创建一个窗口对象,然后我需要能够在没有打字稿的情况下引用它。
      • 你在你的 angular2 组件中使用那个 javascript 方法吗??
      • 我投了反对票,因为你建议了一个不存在的问题的解决方案。当您要求我这样做时,我根据您的添加了 plunkr,以证明这里不需要任何内容​​(OpaqueToken 废话)。说真的,虽然很多人似乎认为 TypeScript 的运行时行为与 JavaScript 不同,但这是不正确的。许多从 Angular 2 开始的人不知道 TypeScript 是什么,并且 Angular 2 教程误导了他们。 99% 的 Angular 2 问题应该有 JavaScript 标签
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-12
      • 2017-01-13
      • 1970-01-01
      • 2018-04-10
      • 2017-08-24
      相关资源
      最近更新 更多