【问题标题】:Angular 2: import external js file into componentAngular 2:将外部js文件导入组件
【发布时间】:2016-09-02 02:11:57
【问题描述】:

我将把这个 d3gauge.js 文件导入我的 angular2 组件之一,memmon.component.ts 文件。

import '../../../../js/d3gauge.js';
export class MemMonComponent {
    createMemGauge() {
        new drawGauge(this.opt);  //drawGauge() is a function inside d3gauge.js
    }
}

并在对应的模板文件中,添加

<script src="../../../../js/d3gauge.js"></script>

但是不行,drawGauge找不到。

所以,

  1. 将外部 js 文件导入 angular2 的正确步骤是什么?
  2. 由于我使用的是webpack,是否可以在webpack中进行?我参考了这个 question ,那里的 webpack 解决方案对我不起作用,因为 .ensure 无法解决。

【问题讨论】:

  • 您需要为文件创建或导入类型 (*.d.ts)。

标签: javascript angular webpack


【解决方案1】:

理想情况下,您需要有 .d.ts 文件用于输入,以让 Linting 工作。

但是d3gauge好像没有,可以请开发者提供,希望他们能听。


或者,您可以通过这样做来解决这个特定问题

declare var drawGauge: any;

import '../../../../js/d3gauge.js';
export class MemMonComponent {
    createMemGauge() {
        new drawGauge(this.opt);  //drawGauge() is a function inside d3gauge.js
    }
}

如果在多个文件中使用,可以创建一个d3gauage.d.ts文件,内容如下

declare var drawGauge: any;

并在顶部的boot.ts (bootstrap) 文件中引用它,像这样

///<reference path="../path/to/d3gauage.d.ts"/>

【讨论】:

  • 谢谢。还有一个问题,declare var drawGauge: any; 在转译这个 ts 文件时什么时候被引用?或者,换句话说,当 new drawGauge(this.opt) 时,编译器如何知道 drawGauge() 实际上在 d3gauge.js 中?
  • 是的,在 transpile 中,它必须知道有/或者将会有一个名为 d3gauge 的东西。在第二个问题中,它没有,d3gauge.js 将其分配给 dom 中的 global 变量,这是在运行时调用它的位置。
  • 我收到了ReferenceError: drawGauge is not defined。是因为我在使用 webpack 吗?
  • 只需将&lt;script src="../../../../js/d3gauge.js"&gt;&lt;/script&gt; 放在您的index.html 中,其他任何地方都没有,webpack 解决方案可能由于路径错误而不起作用,但我对webpack 一无所知
  • @BingLu 嘿伙计,您找到适合您的解决方案了吗?我仍然得到EXCEPTION: Uncaught (in promise): Error: Error in someComponent 说声明的变量is not defined 并且到目前为止找不到解决方案。
【解决方案2】:

在花了很多时间寻找解决方案之后,我找到了一个。为了您的方便,我使用了您可以替换整个文件的完整代码。

这是一个普遍的答案。假设您想将一个名为 testjs.js 的文件导入到您的 Angular 2 组件中。 在您的资产文件夹中创建 testjs.js:

资产 > testjs.js

function test(){
    alert('TestingFunction')
}

在 index.html 中包含 testjs.js

index.html

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>Project1</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">

  <script src="./assets/testjs.js"></script>

</head>
<body>
  <app-root>Loading...</app-root>
</body>
</html>

在您的 app.component.ts 或您要调用此 js 的任何 component.ts 文件中声明一个变量并调用如下函数:

app.component.ts

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

declare var test: any;


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent {
  title = 'app works!';


  f(){
    new test();
  }
}

最后在你的app.component.html测试功能

app.component.html

<h1>
  <button (click)='f()'>Test</button>
</h1>

【讨论】:

  • 我们需要在组件上声明函数名吗,如果我有很多函数我需要声明所有吗?它也不起作用我收到这些错误“错误参考错误:未定义测试”和“拒绝从'localhost:4200/assets/custom.js'执行脚本,因为它的 MIME 类型('text/html')不可执行,并且严格的 MIME 类型检查已启用。”
【解决方案3】:

您可以将其包含在.angular-cli-json 文件中,而不是将您的js 文件扩展名包含在index.html 中。

这些是我完成这项工作所遵循的步骤:

  1. 首先将您的外部js 文件包含在assets/js
  2. .angular-cli.json - 添加脚本下的文件路径: [../app/assets/js/test.js]
  3. 在要使用js文件功能的组件中。

在顶部声明要导入文件的位置

declare const Test:any;

在此之后,您可以访问其功能,例如Test.add()

【讨论】:

  • 嗨,你能告诉我把“Declare const Test:any;”部分放在哪里吗? ?在组件内部?我试图把它放在导出类中,也放在“导出类....”之前,但是没有用。
  • 在您的 app.component.ts 或您要调用 Test 方法的任何 component.ts 文件中,只需在导入其他依赖项的顶部添加“Declare const Test:any”那个组件。
  • declare 不是Declare
【解决方案4】:

以下方法在 Angular 5 CLI 中有效。

为简单起见,我使用了由 Oliverbinns 创建和提供的类似 d3gauge.js 演示 - 您可以在 Github 上轻松找到。

首先,我只是在 assets 文件夹的同一级别上创建了一个名为 externalJS 的新文件夹。然后我复制了以下 2 个 .js 文件。

  • d3.v3.min.js
  • d3gauge.js

然后我确保在主 index.html

中声明两个链接指令
<script src="./externalJS/d3.v3.min.js"></script>
<script src="./externalJS/d3gauge.js"></script>

然后我添加了类似的代码 在 gauge.component.ts 组件中如下:

import { Component, OnInit } from '@angular/core';

declare var d3gauge:any; <----- !
declare var drawGauge: any; <-----!

@Component({
  selector: 'app-gauge',
  templateUrl: './gauge.component.html'
})

export class GaugeComponent implements OnInit {
   constructor() { }

   ngOnInit() {
      this.createD3Gauge();
   }

   createD3Gauge() { 
      let gauges = []
      document.addEventListener("DOMContentLoaded", function (event) {      
      let opt = {
         gaugeRadius: 160,
         minVal: 0,
         maxVal: 100,
         needleVal: Math.round(30),
         tickSpaceMinVal: 1,
         tickSpaceMajVal: 10,
         divID: "gaugeBox",
         gaugeUnits: "%"
    } 

    gauges[0] = new drawGauge(opt);
    });
 }

}

最后,我只是在对应的gauge.component.html中添加了一个div

<div id="gaugeBox"></div>

等等! :)

【讨论】:

    【解决方案5】:

    这是我在项目中使用的一种简单方法。

    假设您需要使用clipboard.min.js 为了这个例子,让我们说在clipboard.min.js里面有一个叫做test2()的函数。

    要使用 test2() 函数,您需要:

    1. 引用 index.html 中的 .js 文件。
    2. clipboard.min.js 导入您的组件。
    3. 声明一个用于调用函数的变量。

    这里只是我项目中的相关部分(参见 cmets):

    index.html:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Angular QuickStart</title>
        <base href="/src/">
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="styles.css">
    
        <!-- Polyfill(s) for older browsers -->
        <script src="/node_modules/core-js/client/shim.min.js"></script>
    
    
        <script src="/node_modules/zone.js/dist/zone.js"></script>
        <script src="/node_modules/systemjs/dist/system.src.js"></script>
    
        <script src="systemjs.config.js"></script>
        <script>
            System.import('main.js').catch(function (err) { console.error(err); });
        </script>
    
        <!-- ************ HERE IS THE REFERENCE TO clipboard.min.js -->
        <script src="app/txtzone/clipboard.min.js"></script>
    </head>
    
    <body>
        <my-app>Loading AppComponent content here ...</my-app>
    </body>
    </html>
    

    app.component.ts:

    import '../txtzone/clipboard.min.js';
    declare var test2: any; // variable as the name of the function inside clipboard.min.js
    
    @Component({
        selector: 'txt-zone',
        templateUrl: 'app/txtzone/Txtzone.component.html',
        styleUrls: ['app/txtzone/TxtZone.css'],
    })
    
    
    
    export class TxtZoneComponent implements AfterViewInit {
    
        // call test2
        callTest2()
        {   
            new test2(); // the javascript function will execute
        }
    
    }
    

    【讨论】:

      【解决方案6】:

      你也可以试试这个:

      import * as drawGauge from '../../../../js/d3gauge.js';
      

      只需在您的 ts 代码中添加 new drawGauge(this.opt);。该解决方案适用于我目前正在研究的 laravel 中嵌入 angular-cli 的项目。就我而言,我尝试从 node_modules 导入 poliglot 库(顺便说一句:非常适合翻译):

      import * as Polyglot from '../../../node_modules/node-polyglot/build/polyglot.min.js';
      ...
      export class Lang 
      {
          constructor() {
      
              this.polyglot = new Polyglot({ locale: 'en' });
              ...
          }
          ...
      }
      

      这个解决方案很好,因为我不需要复制来自node_modules的任何文件:)。

      更新

      您还可以查看 this LIST 了解如何在 angular 中包含库的方法。

      【讨论】:

      • 为我工作:)
      【解决方案7】:

      1) 首先在index.html文件中插入JS文件路径:

      &lt;script src="assets/video.js" type="text/javascript"&gt;&lt;/script&gt;

      2) 导入JS文件并在component.ts中声明变量:

      • 导入'./../../../assets/video.js';
      • 声明 var RunPlayer: 任意;

        注意:变量名应与js文件中的函数名相同

      3) 调用组件中的js方法

      ngAfterViewInit(){
      
          setTimeout(() => {
              new RunPlayer();
          });
      
      }
      

      【讨论】:

        【解决方案8】:

        假设您在 Visual-Studio 的某个 Angular 项目中的 assets/js 文件夹下添加了一个文件“xyz.js”,那么包含该文件的最简单方法是将其添加到 .angular-cli.json

        "scripts": [ "assets/js/xyz.js" ],
        

        您应该能够在您的组件或 .ts 文件中使用此 JS 文件的功能。

        【讨论】:

        • 但对于大型应用程序,列出所有脚本并不理想,因为其中一些脚本将永远不会被使用,因为它们仅适用于特定组件。
        • 怎么用?
        【解决方案9】:

        对于公开多个变量的.js 文件(与drawGauge 不同),更好的解决方案是将Typescript 编译器设置为处理.js 文件。

        在您的 tsconfig.json 中,将 allowJs 选项设置为 true:

        "compilerOptions": {
             ...
            "allowJs": true,
             ...
        }
        

        否则,您必须在 component.tsd.ts 中声明每个变量。

        【讨论】:

          猜你喜欢
          • 2021-10-16
          • 1970-01-01
          • 2017-02-27
          • 1970-01-01
          • 2023-03-08
          • 1970-01-01
          • 1970-01-01
          • 2018-06-04
          • 2017-06-21
          相关资源
          最近更新 更多