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

时间:2016-06-29 01:49:49

标签: javascript angular json-ld angular2-universal

Angular2会自动从模板中删除<script>代码,以阻止人们将此功能用作"poor's man" loader

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

当前使用的是JSON-LD,其格式为

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

一个常见的建议是通过ngAfterViewInit钩子向文档dynamically add script tags,但这显然不是正确的ng2练习,并且不适用于服务器端,JSON-LD显然需要能够做到。

我们可以使用任何其他变通方法在angular2模板中包含<script>标签(即使标签在浏览器中是惰性的),还是这个框架过于自以为是?如果在angular2中无法解决这种情况,可能还有哪些其他解决方案?

6 个答案:

答案 0 :(得分:30)

这里的派对可能有点迟了,但由于上述答案与Angular SSR(例如document is not defined服务器端或document.createElement is not a function)不兼容,我决定编写一个有效的版本对于Angular 4+,服务器和浏览器上下文中的

组件实施

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 s = this._renderer2.createElement('script');
        s.type = `application/ld+json`;
        s.text = `
            {
                "@context": "https://schema.org"
                /* your schema.org microdata goes here */
            }
        `;

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

服务实施

注意:服务无法直接使用Renderer2。实际上,渲染元素应该由Component 完成。但是,您可能会发现自己处于要在页面上自动创建JSON-LD script标记的情况。作为示例,情况可以是在路线导航改变事件上调用这样的功能。因此,我决定添加一个适用于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 s = renderer2.createElement('script');
        s.type = 'application/ld+json';
        s.text = `${JSON.stringify(data)}`;

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

答案 1 :(得分:15)

没有Angular2方法可以向模板添加脚本标记。

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

要动态添加脚本标记,请使用

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);
}

另见angular2: including thirdparty js scripts in component

答案 2 :(得分:10)

以下适用于Angular 5.2.7:

所需的导入是:

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

实施AfterViewInit:

export class HeroesComponent implements AfterViewInit {

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

export class HeroesComponent implements OnInit, AfterViewInit {

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

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

添加视图生命周期的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);
  }

添加afterScriptAdded成员函数。

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

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

答案 3 :(得分:5)

<强>实际上 Angular2 没有向模板添加脚本标记的方法。 但你可以做一些技巧 首先,您将从angular2导入AfterViewInitElementRef 像这样:

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

然后你会在你的班级中实现它们:

export class example1 implements AfterViewInit{}

这是一个非常简单的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
 }
}

答案 4 :(得分:0)

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);

可以将其放置在任何人希望的任何地方,这是一种好方法

答案 5 :(得分:0)

我添加了js脚本,其动态加载方式如下:

    private loadChatWithScript() {
    let chatScript = document.createElement("script");
    chatScript.type = "text/javascript";
    chatScript.async = true;
    chatScript.src = "https://chat-assets.frontapp.com/v1/chat.bundle.js";
    document.body.appendChild(chatScript);

    let chatScriptConfiguration = document.createElement("script");
    chatScriptConfiguration.type = "text/javascript";
    chatScriptConfiguration.async = true;
    chatScriptConfiguration.innerHTML = "window.FCSP = 'some-key-123'";
    document.body.appendChild(chatScriptConfiguration);
}