У меня есть веб-компонент (сделан в angular) с теневым домом. Внутри этого компонента я могу иметь настраиваемый пользователем виджет. Как внешний JS может получить доступ к этому виджету, используя document.getElementsByClassName? Я просто хочу подчеркнуть, что если моя инкапсуляция представления веб-компонента имеет значение None, внешний JS может получить доступ к виджету. Вот пример веб-компонента, где я добавил для краткости жестко закодированный виджет. Если вы включите этот веб-компонент во внешнее приложение, то виджет внутри него не будет виден. Если вы установите ViewEncapsulation на None, вы увидите виджет. Однако мне нужно, чтобы инкапсуляция была ShadowDom и все еще иметь возможность доступа к виджету
import { Component, OnInit, ViewEncapsulation, ViewChild, AfterViewInit, Renderer2 } from '@angular/core';
import { ScriptLoaderService } from '../script-loader/script-loader.service';
@Component({
selector: 'app-panel',
template: `
<slot>
<p>
My panel with custom widget
</p>
<div #parentDiv></div>
</slot>
`,
styles: [],
encapsulation: ViewEncapsulation.ShadowDom
})
export class PanelComponent implements OnInit, AfterViewInit {
@ViewChild('parentDiv', { static: false }) parentDiv;
constructor(
private scriptLoader: ScriptLoaderService,
public renderer: Renderer2
) { }
ngOnInit() {
}
ngAfterViewInit(): void {
this.scriptLoader.loadScript('https://weatherwidget.io/js/widget.min.js').then(() => {
const element: HTMLElement = this.renderer.createElement('a');
element.setAttribute('class', 'weatherwidget-io');
element.setAttribute('href', 'https://forecast7.com/en/40d71n74d01/new-york/');
element.setAttribute('data-label_1', 'NewYork');
element.setAttribute('data-label_2', 'WHEATHER');
element.setAttribute('data-theme', 'original');
element.setAttribute('style', 'height:98px');
this.renderer.appendChild(this.parentDiv.nativeElement, element);
});
}
}
Вот загрузчик скриптов
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class ScriptLoaderService {
private scripts: string[] = [];
loadScript(scriptSource: string): Promise<any> {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.type = 'text/javascript';
script.src = scriptSource;
script.onload = () => {
resolve();
};
script.onerror = (error: any) => reject(error);
document.getElementsByTagName('head')[0].appendChild(script);
});
}
}