我有这个模块,它将外部库与额外的逻辑组件化,而不直接将<script>标记添加到index.html中:
import 'http://external.com/path/file.js'
//import '../js/file.js'
@Component({
selector: 'my-app',
template: `
<script src="http://iknow.com/this/does/not/work/either/file.js"></script>
<div>Template</div>`
})
export class MyAppComponent {...}
我注意到ES6规范的导入是静态的,并且是在TypeScript编译期间解析的,而不是在运行时。
总之,让它变得可配置,这样file。js就会从CDN或本地文件夹加载?
如何告诉Angular 2动态加载脚本?
我希望能够:
Add a script when the app is being bootstrapped
Not do it from a component, because it doesn't feel like it's any component's responsibility
Not do it from a directive, because of the same reason as the component
Not do it from a service, because unless there's some kind of heavy logic related to an existing service, this doesn't belong IMO to a service
Avoid doing it in a module. A module could be fine but it's not as flexible as just using DI and since Angular 15 standalone components are stable so why bother with a module
也就是说,为了在应用程序引导之前做到这一点,这有点棘手。因为我们在那个阶段没有可用的渲染器,并且我们不能访问包含nativeElement的elementRef。
下面是我的看法:
export const YOUR_EXT_LIB_URL_TOKEN = new InjectionToken<string>('YOUR_EXT_LIB_URL_TOKEN');
export const YOUR_SETUP: Provider = {
provide: APP_INITIALIZER,
multi: true,
useFactory: (
doc: InjectionTokenType<typeof DOCUMENT>,
rendererFactory: RendererFactory2,
yourExternalLibToken: string,
) => {
const renderer = rendererFactory.createRenderer(null, null);
const script = renderer.createElement('script');
script.type = 'text/javascript';
script.src = yourExternalLibToken;
renderer.appendChild(doc.body, script);
return () => true;
},
deps: [DOCUMENT, RendererFactory2, YOUR_EXT_LIB_URL_TOKEN],
};
然后,您所要做的就是提供YOUR_EXT_LIB_URL_TOKEN并传递YOUR_SETUP提供程序。
这样,所有东西都是通过DI注入的,非常灵活。例如,您可以在共享库中提供YOUR_SETUP令牌,并在使用共享库的不同应用程序中提供YOUR_EXT_LIB_URL_TOKEN。
如果你正在使用system.js,你可以在运行时使用System.import():
export class MyAppComponent {
constructor(){
System.import('path/to/your/module').then(refToLoadedModule => {
refToLoadedModule.someFunction();
}
);
}
如果你正在使用webpack,你可以充分利用它强大的代码分割支持。确保:
export class MyAppComponent {
constructor() {
require.ensure(['path/to/your/module'], require => {
let yourModule = require('path/to/your/module');
yourModule.someFunction();
});
}
}
我发现这个解决方案更干净,首先在你的模块中导入HttpClientJsonpModule,然后做这样的事情
this.apiLoaded = this.httpClient.jsonp(environment.AnyApiUrl, 'callback')
.pipe(
map(() => true),
catchError(() => of(false)),
);
在模板中:
<app-component *ngIf="apiLoaded | async"></app-component>
这个解决方案在Angular谷歌Maps的官方文档中。
@ rahull -kumar的解决方案对我来说很好,但我想在我的typescript中调用我的javascript函数
foo.myFunctions() // works in browser console, but foo can't be used in typescript file
我通过在我的typescript中声明它来修复它:
import { Component } from '@angular/core';
import { ScriptService } from './script.service';
declare var foo;
现在,我可以在typcript文件的任何地方调用foo