You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AEM 6.5+SPA+Angular 9:子组件如何订阅父容器组件?

在AEM 6.5 Angular 9 SPA中子组件订阅父组件变更的实现方案

一、获取最近父组件引用并订阅变更

1. Angular依赖注入(直接父组件场景)

如果子组件是直接嵌套在目标父组件内,使用@Optional()+@SkipSelf()注入最近的父组件实例是最高效的方式:

子组件代码:

import { Component, OnInit, Optional, SkipSelf, OnDestroy } from '@angular/core';
import { ParentComponent } from './parent.component';
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit, OnDestroy {
  private parentSub: Subscription;
  parentBgColor: string;
  parentId: string;
  textColor = '#000000';

  constructor(
    @Optional() @SkipSelf() private parentComp: ParentComponent
  ) { }

  ngOnInit(): void {
    if (!this.parentComp) return;

    // 订阅父组件背景色变更
    this.parentSub = this.parentComp.bgColorChange$.subscribe(color => {
      this.parentBgColor = color;
      this.adjustTextColor();
    });
    // 获取父组件ID
    this.parentId = this.parentComp.componentId;
  }

  ngOnDestroy(): void {
    this.parentSub?.unsubscribe();
  }

  // 根据背景色计算适配文本颜色
  private adjustTextColor(): void {
    const rgb = this.hexToRgb(this.parentBgColor);
    const brightness = (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000;
    this.textColor = brightness > 125 ? '#000000' : '#ffffff';
  }

  private hexToRgb(hex: string): {r: number, g: number, b: number} {
    const match = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    return match ? {
      r: parseInt(match[1], 16),
      g: parseInt(match[2], 16),
      b: parseInt(match[3], 16)
    } : { r: 255, g: 255, b: 255 };
  }
}

父组件代码(需暴露可订阅的属性流):

import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.css']
})
export class ParentComponent implements OnChanges {
  @Input() bgColor = '#ffffff';
  @Input() componentId: string;
  private bgColor$ = new BehaviorSubject<string>(this.bgColor);
  // 对外暴露可订阅的变更流
  bgColorChange$ = this.bgColor$.asObservable();

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.bgColor) {
      this.bgColor$.next(changes.bgColor.currentValue);
    }
  }
}

2. AEM ModelManager遍历(跨容器场景)

如果子组件和父组件之间隔了AEM系统容器组件,使用ModelManager遍历组件模型的父层级,找到最近的目标父组件:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { ModelManager, Model } from '@adobe/aem-spa-page-model-manager';
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit, OnDestroy {
  private modelSub: Subscription;
  parentBgColor: string;
  parentId: string;
  textColor = '#000000';

  ngOnInit(): void {
    const componentPath = this.getComponentPath();
    if (!componentPath) return;

    // 订阅当前组件模型变更
    this.modelSub = ModelManager.getInstance().getData(componentPath).subscribe(model => {
      this.findClosestParent(model);
    });
  }

  // 获取当前组件的AEM路径(从DOM属性提取)
  private getComponentPath(): string {
    const elem = document.querySelector('app-child');
    return elem?.getAttribute('data-cq-path') || '';
  }

  // 向上遍历父模型,找到目标父组件
  private findClosestParent(currentModel: Model): void {
    let parentModel = currentModel[':parent'];
    while (parentModel) {
      // 通过资源类型判断是否是目标父组件
      if (parentModel['sling:resourceType'] === 'your-project/components/parent-container') {
        this.parentBgColor = parentModel['bgColor'];
        this.parentId = parentModel[':id'];
        this.adjustTextColor();
        // 订阅父模型变更
        this.subscribeToParent(parentModel[':path']);
        break;
      }
      parentModel = parentModel[':parent'];
    }
  }

  private subscribeToParent(parentPath: string): void {
    this.modelSub.add(
      ModelManager.getInstance().getData(parentPath).subscribe(updatedParent => {
        this.parentBgColor = updatedParent['bgColor'];
        this.adjustTextColor();
      })
    );
  }

  ngOnDestroy(): void {
    this.modelSub?.unsubscribe();
  }

  private adjustTextColor(): void {
    const rgb = this.hexToRgb(this.parentBgColor);
    const brightness = (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000;
    this.textColor = brightness > 125 ? '#000000' : '#ffffff';
  }

  private hexToRgb(hex: string): {r: number, g: number, b: number} {
    const match = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    return match ? {
      r: parseInt(match[1], 16),
      g: parseInt(match[2], 16),
      b: parseInt(match[3], 16)
    } : { r: 255, g: 255, b: 255 };
  }
}

二、组件拖拽时的监听方案

Angular本身没有直接监听AEM组件拖拽的事件,但可以通过两种方式触发组件逻辑更新:

  • ModelManager全局事件:组件拖拽完成后,AEM会更新页面模型,ModelManager会发出modelChanged事件:
    ModelManager.getInstance().getEvents().subscribe(event => {
      if (event.type === 'modelChanged') {
        // 拖拽完成后重新获取父组件信息
        const componentPath = this.getComponentPath();
        if (componentPath) {
          ModelManager.getInstance().getData(componentPath).subscribe(model => {
            this.findClosestParent(model);
          });
        }
      }
    });
    
  • DOM MutationObserver:监听DOM节点插入,判断组件是否被放入目标父容器:
    ngAfterViewInit(): void {
      const observer = new MutationObserver(mutations => {
        mutations.forEach(mut => {
          if (mut.addedNodes.length && this.elementRef.nativeElement.parentElement) {
            const parentIsTarget = this.elementRef.nativeElement.parentElement
              .matches('[data-cq-path*="parent-container"]');
            if (parentIsTarget) {
              this.findClosestParent(this.getCurrentModel());
            }
          }
        });
      });
      observer.observe(document.body, { childList: true, subtree: true });
      // 记得在ngOnDestroy中调用observer.disconnect()
    }
    

三、场景适配

  1. 背景色与文本颜色适配:子组件获取父组件背景色后,通过颜色亮度计算逻辑动态切换文本颜色,确保在任何背景色下文本都可读。
  2. 父组件ID获取:依赖注入方案直接从父组件实例取componentId;ModelManager方案从父模型的:id属性提取,用于构建后端数据结构。

内容的提问来源于stack exchange,提问作者David

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 20:14:52