Angular 2:将外部js文件导入组件

66

我将把这个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
    }
}

在相应的模板文件中,添加 <\/p>。
<script src="../../../../js/d3gauge.js"></script>

但它没有起作用,drawGauge无法找到。
所以,
1. 导入外部js文件到angular2的正确步骤是什么? 2. 由于我正在使用webpack,是否可以在webpack中实现?我参考了这个问题,那里的webpack解决方案对我来说无效,因为.ensure无法解析。

2
您需要为该文件创建或导入 typings (*.d.ts)。 - ps2goat
9个回答

81

理想情况下,您需要拥有 .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"/>

1
谢谢。另一个问题,declare var drawGauge: any; 什么时候被引用,在转译这个ts文件的时候吗?或者换一种说法,当 new drawGauge(this.opt) 时,编译器如何知道 drawGauge() 实际上在 d3gauge.js 中? - Bing Lu
是的,在转换时,它必须知道有一个名为d3gauge的东西存在或将要存在。在第二个问题中,它不需要,因为d3gauge.js将其分配给dom中的一个global变量,这就是运行时它被调用的地方。 - Ankit Singh
我得到了 ReferenceError: drawGauge is not defined。这是因为我使用了webpack吗? - Bing Lu
1
只需将<script src="../../../../js/d3gauge.js"></script>放置在您的index.html文件中,无需在其他任何地方添加。Webpack解决方案可能由于错误路径而无法工作,但我对webpack一无所知。 - Ankit Singh
1
@BingLu 嘿,伙计,你解决问题了吗?我仍然得到 EXCEPTION: Uncaught (in promise): Error: Error in someComponent 的错误提示,说声明的变量未定义,到目前为止还没有找到解决方案。 - Mr.Moe
显示剩余2条评论

56

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

这是一个通用的答案。假设你想将名为testjs.js的文件导入到你的Angular 2组件中。请在你的assets文件夹中创建testjs.js:

assets > testjs.js

function test(){
    alert('TestingFunction')
}
Include testjs.js in your index.html.
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或任何想要调用此JavaScript的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>

1
我们需要在组件上声明函数名吗?如果我有很多函数,我需要全部声明吗?另外,它没有工作,我得到了这些错误:“ERROR ReferenceError: test is not defined”和“Refused to execute script from 'http://localhost:4200/assets/custom.js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled." - Sunil Chaudhary

15

可以将你的js文件扩展名添加到.angular-cli-json文件中,而不是在index.html中包含它。

以下是我遵循的步骤:

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

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

declare const Test:any;

之后,您可以像这样访问其函数:Test.add()


你好,能告诉我在哪里放置 "Declare const Test:any;" 这部分代码吗?是放在组件内部吗?我尝试将其放在 export class 内部和 export class 前面,但都没有起作用。 - Vladimir Despotovic
在您的app.component.ts文件或任何组件.ts文件中,如果您想调用Test方法,只需在导入该组件的其他依赖项的顶部添加“Declare const Test:any”。 - Sitaram
declare not Declare - Jnr

6
以下方法适用于Angular 5 CLI。
为了简单起见,我使用了由oliverbinns创建和提供的类似d3gauge.js演示 - 您可以轻松在Github上找到它。
所以首先,我只是在与assets文件夹相同的级别上创建了一个名为externalJS的新文件夹。然后我复制了以下两个.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>

et voilà!:)

enter image description here


4

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

假设您需要使用 clipboard.min.js,并且为了举例,让我们假设在 clipboard.min.js 中有一个名为 test2() 的函数。

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

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

以下仅是我项目中相关部分(请参见注释):

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
    }

}

3

对于暴露不止一个变量的 .js 文件(与 drawGauge 不同),更好的解决方案是设置 Typescript 编译器处理 .js 文件。

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

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

否则,你需要在component.tsd.ts中声明每个变量。

2
你也可以尝试这个方法:
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 复制任何文件 :)。

更新

您还可以查看此列表,了解如何在Angular中包含库的其他方式。


对我有用 :) - Naveen Kumar V

1

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

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

你应该能够在你的组件或 .ts 文件中使用这个 JS 文件的功能。

1
但是对于一个大型应用程序来说,在那里列出所有的脚本并不理想,因为其中一些脚本永远不会被使用,因为它们只针对特定的组件。 - Pran Kumar Sarkar
我们如何使用? - Yasar Arafath

1

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

<script src="assets/video.js" type="text/javascript"></script>

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

  • import './../../../assets/video.js';
  • declare var RunPlayer: any;

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

3) 在组件中调用js方法

ngAfterViewInit(){

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

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接