Javascript 在 Angular 组件模板中添加脚本标签

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38088996/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 21:04:59  来源:igfitidea点击:

Adding script tags in Angular component template

javascriptangularjson-ldangular2-universal

提问by Ian Belcher

Angular2 removes <script>tags automatically from templates to stop people using this functionality as a "poor's man" loader.

Angular2 会<script>自动从模板中删除标签,以阻止人们将此功能用作“穷人”加载器

The issue here is that script tags currently have more uses than just loading code or other script files. There is the possibility that further functionality around <script>tags will be introduced in future as well.

这里的问题是脚本标签目前的用途不仅仅是加载代码或其他脚本文件。<script>将来也有可能会引入更多围绕标签的功能。

One current use is JSON-LD which takes the format

目前的一种用途是采用以下格式的 JSON-LD

<script type="application/ld+json">
{
    "@context":"http://schema.org",
    "@type":"HealthClub",
    ...
}
</script>

A commonly suggested work around is to dynamically add script tagsto the document via the ngAfterViewInithook, but this is obviously not proper ng2 practice and will not work server side, which JSON-LD obviously needs to be able to do.

通常建议的解决方法是通过钩子将脚本标签动态添加到文档中ngAfterViewInit,但这显然不是 ng2 的正确做法,并且不会在服务器端工作,而 JSON-LD 显然需要能够做到这一点。

Are there any other workarounds that we can use to include <script>tags in angular2 templates (even if the tag is inert within the browser) or is this a case of the framework being too opinionated? What other solutions might exist if this situation can't be solved in angular2?

是否有任何其他解决方法可用于<script>在 angular2 模板中包含标签(即使标签在浏览器中是惰性的),或者这是框架过于固执的情况吗?如果在 angular2 中无法解决这种情况,还有哪些其他解决方案?

采纳答案by Nicky

Maybe a little late to the party here, but since the above answers do not work well with Angular SSR (e.g. document is not definedserver-side or document.createElement is not a function), I decided to write a version that works for Angular 4+, in both server and browser context:

也许在这里聚会有点晚了,但是由于上述答案不适用于 Angular SSR(例如document is not defined服务器端或document.createElement is not a function),我决定编写一个适用于 Angular 4+ 的版本,在服务器和浏览器上下文中

Component Implementation

组件实现

import { Renderer2, OnInit, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';

class MyComponent implements OnInit {

    constructor(
        private _renderer2: Renderer2, 
        @Inject(DOCUMENT) private _document: Document
    ) { }

    public ngOnInit() {

        let script = this._renderer2.createElement('script');
        script.type = `application/ld+json`;
        script.text = `
            {
                "@context": "https://schema.org"
                /* your schema.org microdata goes here */
            }
        `;

        this._renderer2.appendChild(this._document.body, script);
    }
}

Service Implementation

服务实施

NOTE: Services cannot use Renderer2directly. In fact, rendering an element is supposed to be done by a Component. However, you might find yourself in situation where you want to automate the creation of JSON-LD scripttags on a page. As an example, a situation could be to invoke such function on route navigation change events. Hence I decided to add a version that works in a Servicecontext.

注意:服务不能Renderer2直接使用。实际上,渲染元素应该由 Component 完成。但是,您可能会发现自己希望script在页面上自动创建 JSON-LD标签。例如,一种情况可能是在路线导航更改事件上调用此类函数。因此我决定添加一个在Service上下文中工作的版本。

import { Renderer2, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';

/**
 * Use a Service to automate creation of JSON-LD Microdata.
 */
class MyService {

    constructor(
        @Inject(DOCUMENT) private _document: Document
    ) { }

    /**
     * Set JSON-LD Microdata on the Document Body.
     *
     * @param renderer2             The Angular Renderer
     * @param data                  The data for the JSON-LD script
     * @returns                     Void
     */
    public setJsonLd(renderer2: Renderer2, data: any): void {

        let script = renderer2.createElement('script');
        script.type = 'application/ld+json';
        script.text = `${JSON.stringify(data)}`;

        renderer2.appendChild(this._document.body, script);
    }
}

回答by Günter Z?chbauer

There is no Angular2 way of adding a script tag to a template.

没有将脚本标记添加到模板的 Angular2 方法。

Using require(...)to load external scripts from the components class was mentioned as a workaround (haven't tried it myself)

使用require(...)从组件类加载外部脚本被认为是一种解决方法(我自己没有尝试过)

To dynamically add a script tag use

动态添加脚本标签使用

constructor(private elementRef:ElementRef) {};

ngAfterViewInit() {
  var s = document.createElement("script");
  s.type = "text/javascript";
  s.src = "http://somedomain.com/somescript";
  this.elementRef.nativeElement.appendChild(s);
}

See also angular2: including thirdparty js scripts in component

另请参阅angular2:在组件中包含第三方 js 脚本

回答by Ketan Yekale

The following works with Angular 5.2.7:

以下适用于 Angular 5.2.7:

The required imports are:

所需的进口是:

import { Inject, AfterViewInit, ElementRef } from '@angular/core';
import { DOCUMENT } from '@angular/common';

Implement AfterViewInit:

实现 AfterViewInit:

export class HeroesComponent implements AfterViewInit {

If your component is implementing more that one interfaces, separate them by comma; for example:

如果您的组件正在实现多个接口,请用逗号分隔它们;例如:

export class HeroesComponent implements OnInit, AfterViewInit {

Pass the below arguments to constructor:

将以下参数传递给构造函数:

constructor(@Inject(DOCUMENT) private document, private elementRef: ElementRef) { }

Add ngAfterViewInit method of view life-cycle:

添加视图生命周期的 ngAfterViewInit 方法:

ngAfterViewInit() {
    const s = this.document.createElement('script');
    s.type = 'text/javascript';
    s.src = '//external.script.com/script.js';
    const __this = this; //to store the current instance to call 
                         //afterScriptAdded function on onload event of 
                         //script.
    s.onload = function () { __this.afterScriptAdded(); };
    this.elementRef.nativeElement.appendChild(s);
  }

Add afterScriptAdded member function.

添加 afterScriptAdded 成员函数。

This function will be called after the external script is loaded successfully. So the properties or functions you want to use from external js will be accessed in the body of this function.

该函数会在外部脚本加载成功后调用。因此,您要从外部 js 使用的属性或函数将在此函数的主体中访问。

 afterScriptAdded() {
    const params= {
      width: '350px',
      height: '420px',
    };
    if (typeof (window['functionFromExternalScript']) === 'function') {
      window['functionFromExternalScript'](params);
    }
  }

回答by Mohsen M. Galal

ActuallyThere is no Angular2way of adding a script tagto a template. but you can do some trickfirst of allyou will import AfterViewInitand ElementReffrom angular2 like this :

实际上,没有Angular2方法可以将脚本标记添加到模板中。但你可以先做一些技巧你将像这样从 angular2导入AfterViewInit和导入ElementRef

import {Component,AfterViewInit,ElementRef} from 'Angular2/core';

thenyou will you will implement them in your class like that :

那么你会像这样在你的班级中实现它们:

export class example1 implements AfterViewInit{}

and here is a very simple javascript dom trick you gonna do

这是你要做的一个非常简单的javascript dom技巧

 export class example1 implements AfterViewInit{
 ngAfterViewInit()
 {
  var s=document.createElement("script");
  s.type="text/javascript";
  s.innerHTML="console.log('done');"; //inline script
  s.src="path/test.js"; //external script
 }
}

回答by Giggs

const head = document.getElementsByTagName('head')[0];
const _js = document.createElement('script');
_js.type = 'text/javascript';
_js.appendChild(document.createTextNode('{your js code here}'));
head.appendChild(_js);

this can be placed anywhere one wishes and it's a good approach

这可以放在任何你想要的地方,这是一个很好的方法