切换语言为:繁体

Angular 中实现多窗口页面应用

  • 爱糖宝
  • 2024-11-12
  • 2025
  • 0
  • 0

在现代的 Web 应用中,处理多窗口或多标签页的场景并不常见,但有时我们确实需要模拟桌面应用的多窗口管理功能。本文将介绍如何在 Angular 中设计一个多窗口页面应用,确保每个打开的窗口都是唯一的,并且能够保存其打开的状态。我们还会演示如何在主页面更新子窗口的数据,并且让子窗口聚焦。

需求背景

  • 唯一窗口:每个打开的窗口都应该是唯一的,不能重复。

  • 状态保存:每个窗口都需要能够保存其打开状态(例如,某些数据或交互状态)。

  • 动态更新:能够在主页面点击按钮时更新已打开窗口的数据,并且更新后该窗口应该聚焦。

实现步骤

1. 创建 WindowManagerService 管理窗口

WindowManagerService 是管理多个窗口的核心服务,它负责打开新窗口、发送数据更新并确保窗口聚焦。

// window-manager.service.ts
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class WindowManagerService {
  private windows: { [name: string]: Window | null } = {};

  // 打开窗口并发送初始数据
  openWindow(path: string, name: string, params: { [key: string]: any }) {
    const paramString = new URLSearchParams(params).toString();
    const fullUrl = `${window.location.origin}${path}?${paramString}`;

    // 检查是否已有同名窗口
    if (this.windows[name] && !this.windows[name]?.closed) {
      this.windows[name]?.focus(); // 聚焦到现有窗口
    } else {
      // 打开新的窗口
      const newWindow = window.open(fullUrl, name, 'width=800,height=600');
      this.windows[name] = newWindow;

      // 当窗口关闭时,从字典中移除
      newWindow?.addEventListener('beforeunload', () => {
        delete this.windows[name];
      });
    }
  }

  // 发送更新数据到指定窗口并聚焦
  updateWindowData(name: string, data: any) {
    const window = this.windows[name];
    if (window && !window.closed) {
      window.postMessage(data, window.location.origin); // 向窗口发送数据
      window.focus();  // 聚焦到该窗口
    }
  }
}

代码解释
  • openWindow:负责打开一个新窗口或聚焦到已有窗口。

  • updateWindowData:向已打开的窗口发送数据更新,并聚焦该窗口。

2. 在 AppComponent 中调用更新方法

主页面组件将负责打开新的窗口和更新已打开窗口的数据。点击按钮后,我们将调用 WindowManagerService 来打开新窗口和更新数据。

// app.component.ts
import { Component } from '@angular/core';
import { WindowManagerService } from './window-manager.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  constructor(private windowManager: WindowManagerService) {}

  // 打开新窗口
  openNewWindow(windowName: string) {
    const path = '/window'; // 路由路径
    this.windowManager.openWindow(path, windowName, { windowId: windowName });
  }

  // 更新窗口数据
  updateWindowData(windowName: string) {
    const updatedData = { message: '更新的数据' }; // 这里是要发送的更新数据
    this.windowManager.updateWindowData(windowName, updatedData);
  }
}

代码解释
  • openNewWindow:用于打开新的窗口。

  • updateWindowData:用于更新已打开窗口的数据。

3. 在 WindowComponent 中监听数据更新

每个窗口组件需要监听来自主页面的消息(使用 postMessage)并根据收到的数据更新其内容。

// window.component.ts
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-window',
  templateUrl: './window.component.html',
  styleUrls: ['./window.component.css']
})
export class WindowComponent implements OnInit {
  windowId!: string;
  data: any = {};

  ngOnInit() {
    // 监听父窗口发送的消息
    window.addEventListener('message', (event: MessageEvent) => {
      if (event.origin === window.location.origin) {  // 确保来源正确
        this.data = event.data;  // 接收数据并更新组件
      }
    });
  }
}

代码解释
  • ngOnInit:在组件初始化时,监听来自父窗口的消息,并根据数据更新视图。

4. window.component.html 展示数据

<div *ngIf="windowId">
  <h2>窗口 {{ windowId }}</h2>
  <p>窗口中的数据: {{ data.message }}</p>
</div>

5. 修改主页面的按钮来更新窗口

在主页面,您可以添加按钮来更新窗口中的数据。点击更新按钮时,窗口中的数据将被动态更新。

<div>
  <h1>多窗口管理示例</h1>
  <button (click)="openNewWindow('Window1')">打开窗口 1</button>
  <button (click)="openNewWindow('Window2')">打开窗口 2</button>
  <button (click)="openNewWindow('Window3')">打开窗口 3</button>

  <!-- 更新窗口数据 -->
  <button (click)="updateWindowData('Window1')">更新窗口 1 数据</button>
  <button (click)="updateWindowData('Window2')">更新窗口 2 数据</button>
  <button (click)="updateWindowData('Window3')">更新窗口 3 数据</button>
</div>

<router-outlet></router-outlet>

流程总结

  1. 打开窗口:点击 "打开窗口 1" 等按钮时,窗口会被打开,并显示唯一的 windowId

  2. 更新数据:点击 "更新窗口 1 数据" 等按钮时,updateWindowData 会向目标窗口发送更新数据,并聚焦该窗口。

  3. 窗口监听更新:每个子窗口通过 postMessage 接收来自主页面的数据,并更新其视图。

小结

通过这种方式,我们能够在 Angular 中实现多窗口管理,并且每个窗口都能保存其状态。在更新数据时,还能确保子窗口聚焦,提升了用户体验。这种方法适合需要多个独立窗口管理的场景,例如在桌面应用风格的 Web 应用中。


作者:KirovReporting
链接:https://juejin.cn/post/7435643017149366326

0条评论

您的电子邮件等信息不会被公开,以下所有项均必填

OK! You can skip this field.