Добавление тегов скрипта в шаблон компонента Angular
Angular2 удаляет <script>
автоматически теги из шаблонов, чтобы люди не использовали эту функцию в качестве загрузчика "бедняков".
Проблема здесь в том, что теги сценариев в настоящее время имеют больше применений, чем просто загрузка кода или других файлов сценариев. Существует вероятность того, что дальнейшая функциональность вокруг <script>
теги будут введены и в будущем.
В настоящее время используется формат JSON-LD, который принимает формат
<script type="application/ld+json">
{
"@context":"http://schema.org",
"@type":"HealthClub",
...
}
</script>
Обычно предлагается обходной путь - динамически добавлять теги сценария в документ через ngAfterViewInit
хук, но это явно не правильная практика ng2 и не будет работать на стороне сервера, что JSON-LD, очевидно, должен уметь делать.
Существуют ли другие обходные пути, которые мы можем использовать, чтобы включить <script>
тэги в шаблонах angular2 (даже если тэг инертен в браузере) или в этом случае фреймворк слишком самоуверенный? Какие другие решения могут существовать, если эта ситуация не может быть решена в angular2?
7 ответов
Может быть, немного опоздал на вечеринку здесь, но так как вышеупомянутые ответы не работают хорошо с 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/platform-browser';
class MyComponent implements OnInit {
constructor(private _renderer2: Renderer2, @Inject(DOCUMENT) private _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
непосредственно. Фактически, рендеринг элемента должен выполняться Компонентом. Однако вы можете оказаться в ситуации, когда вы хотите автоматизировать создание JSON-LD. script
теги на странице. Ситуация может состоять в том, чтобы вызвать такую функцию на событиях изменения навигации маршрута. Поэтому я решил добавить версию, которая работает в Service
контекст.
import { Renderer2, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/platform-browser';
class MyService {
constructor(@Inject(DOCUMENT) private _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);
}
}
В 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: включение сторонних js-скриптов в компонент
Следующее работает с 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);
}
}
На самом деле нет никакого Angular2 способа добавления тега script в шаблон. но вы можете сделать какой-то трюк,прежде всего вы будете импортировать AfterViewInit
а также ElementRef
от angular2 вот так:
import {Component,AfterViewInit,ElementRef} from 'Angular2/core';
тогда вы будете реализовывать их в своем классе так:
export class example1 implements AfterViewInit{}
и вот очень простой трюк с Ja vaScript, который ты собираешься делать
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
}
}
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);
это можно разместить где угодно, и это хороший подход
Я добавил динамическую загрузку 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);
}
Джентльмен/джентльмен, пожалуйста, взгляните.
Для добавления пиксельных сценариев это может сэкономить ваше время. Это решение проще, чем любая разработка:
- Работает только на первой загруженной странице -
Находить
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Angular Application</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
<script>
// Put your script here
alert('Test me, Angular hero!');
</script>
</body>
</html>
Для использования скрипта внутри шаблона углового компонента я предлагаю ответ @Nicky.