我有一个Angular应用程序,需要在其中加载多个iframe。我在iframe中加载的网页也是使用Angular构建的。如果我这样写HTML
<div id="frame">
<div>
<iframe id='iframeId0' [src]=sanitizedURL [height]="iFrameHeight" width="100%" frameborder="0"></iframe>
</div>
<div>
<iframe id='iframeId1' [src]=sanitizedURL [height]="iFrameHeight" width="100%" frameborder="0"></iframe>
</div>
<div>
<iframe id='iframeId2' [src]=sanitizedURL [height]="iFrameHeight" width="100%" frameborder="0"></iframe>
</div>
<div>
<iframe id='iframeId3' [src]=sanitizedURL [height]="iFrameHeight" width="100%" frameborder="0"></iframe>
</div>
<div>
<iframe id='iframeId4' [src]=sanitizedURL [height]="iFrameHeight" width="100%" frameborder="0"></iframe>
</div>
</div>
我可以使用postMessage这样将数据发送到iframe:
ngOnInit() {
for (let i = 0; i < this.numberOfIframes; i++) {
this.iframeData.push({ url: '', iframeNumber: i });
}
this.dbService.dbData$.subscribe(dbData => {const message: PmData = {
command: 'url
payload: url,
}
const win = window.frames[this.pdfFrame];
win.postMessage(JSON.stringify(message), environment.docViewerUrl);
可以观察到dbData $来存储数据。 数据是通过另一个Angular应用程序在iframe中接收的,其中添加了事件侦听器,如下所示:
ngOnInit() {
window.addEventListener("message", async (event) => {
console.log('called from', event.origin);
它工作正常。
如果我这样使用* ngFor:
<div *ngFor="let frame of iframeData">
<iframe [src]=sanitizedURL [height]="iFrameHeight" width="100%" frameborder="0"></iframe>
</div>
并像上面一样发送postMessage,我从没收到任何消息。为什么会这样,我该如何解决?
作为@ConnorsFan建议,我尝试了以下操作:
<div id="frame">
<div #iframeContainer *ngFor="let iframe of iframeData">
<div [hidden]="pdfFrame !== 0">
<iframe [src]=sanitizedURL [height]="iFrameHeight" width="100%" frameborder="0"></iframe>
</div>
</div>
export class OneComponent implements OnInit, AfterViewInit {
@ViewChildren('iframeContainer') iframeContainers: QueryList<ElementRef>;
sanitizedURL: SafeResourceUrl;
pdfFrame = 0;
docIdx = 0;
iFrameHeight = '';
numberOfIframes = 5;
dbData: DbData;
pageNumber = 1;
pdfLoading = false;
iframeData: IframeData[] = [];
constructor(
private sanitizer: DomSanitizer,
private dbService: DbService
) { }
ngOnInit() {
console.log('one ngOnInit');
for (let i = 0; i < this.numberOfIframes; i++) {
this.iframeData.push({ url: '', iframeNumber: i });
}
const docId = document.getElementById('frame'); // I can't get height=100% to work in the HTML
this.iFrameHeight = `${docId.clientHeight - 20}px`;
this.sanitizedURL = this.sanitizer.bypassSecurityTrustResourceUrl(environment.docViewerURL);
}
async ngAfterViewInit() {
this.dbData = await this.dbService.dbData$.pipe(first()).toPromise();
//await this.iframeContainers.changes.pipe(first()).toPromise();
this.iframeContainers.changes.subscribe((list: QueryList<ElementRef>) => {
console.log('iframeContainers.changes', list);
});
this.handleLoadedDocs(this.dbData.docs[this.pdfFrame].downloadURL);
this.dbService.dbData$.subscribe(dbData => this.dbData = dbData);
window.addEventListener('message', async (event) => {
if (typeof event.data === 'string') {
const responce = JSON.parse(event.data);
if (responce.command === 'PdfLoaded') {
this.pdfLoading = false;
}
}
});
}
private handleLoadedDocs(url: string) {
if (this.pdfLoading) return;
const idx = this.iframeData.findIndex(data => data.url === url);
if (idx >= 0) {
// URL is already loaded, make it active
this.pdfFrame = this.iframeData[idx].iframeNumber;
// and move it to the top array position
const topIframe = this.iframeData.splice(idx, 1);
this.iframeData.push(topIframe[0]);
} else {
const oldIframe = this.iframeData.shift();
this.iframeData.push({ url: url, iframeNumber: oldIframe.iframeNumber });
this.pdfFrame = oldIframe.iframeNumber;
// send URL to doc-viewer
this.sendCommandToPdfViewer(PdfViewerCommand.URL, url);
}
console.log('this.iframeData', this.iframeData);
}
private sendCommandToPdfViewer(command: PdfViewerCommand, payload: any) {
const message = {
command,
payload,
}
const win = window.frames[this.pdfFrame];
win.postMessage(message, environment.docViewerURL);
}
使用此代码,我在日志中获得以下输出:
QueryList {dirty: false, _results: Array(5), changes: EventEmitter, length: 5, last: ElementRef, …}
changes: EventEmitter {_isScalar: false, observers: Array(1), closed: false, isStopped: false, hasError: false, …}
dirty: false
first: ElementRef {nativeElement: div}
last: ElementRef {nativeElement: div}
length: 5
_results: (5) [ElementRef, ElementRef, ElementRef, ElementRef, ElementRef]
__proto__: Object
,但是如果我移动this.handleLoadedDocs(this.dbData.docs[this.pdfFrame].downloadURL);
进入iframeContainers订阅(这是我想我需要做的吗?),日志中什么也没有。因此,看起来我必须发送一些内容才能发出iframeContainers订阅。那我想念什么?
答案 0 :(得分:0)
我想我已经知道了,至少该解决方案可以在Mac上的Chrome,Firefox和Safari中使用。
我的HTML:
<div id="frame">
<div *ngFor="let dummy of ' '.repeat(numberOfIframes).split(''); let i = index">
<div [hidden]="activeFrame !== i">
<iframe #iframeContainer [src]=sanitizedURL [height]="iFrameHeight" width="100%" frameborder="0"></iframe>
</div>
</div>
</div>
在.ts文件中:
export class OneComponent implements OnInit, AfterViewInit {
@ViewChildren('iframeContainer') iframeContainers: QueryList<ElementRef>;
...
ngAfterViewInit() {
this.iframeContainers.forEach(_iframe => {
this.iframeRefs.push(_iframe);
});
然后我可以与每个iframe通信:
const win = this.iframeRefs[iframeIdx].nativeElement.contentWindow;
win.postMessage(message, environment.docViewerURL);