Angular - 视图查询与内容查询区别及应用

在Angular中,视图查询(View Query)内容查询(Content Query) 都是用于获取子元素或组件的机制,但它们的查询范围和应用场景有本质区别。以下是详细对比:


核心区别

特性 视图查询(@ViewChild / @ViewChildren 内容查询(@ContentChild / @ContentChildren
查询范围 组件自身模板内的元素 通过<ng-content>投影到组件中的内容(来自父组件)
生命周期钩子 结果在 ngAfterViewInit 中可用 结果在 ngAfterContentInit 中可用
用途 操作组件内部的子组件/DOM元素 操作外部传入的投影内容
装饰器类型 @ViewChild(单个)
@ViewChildren(多个)
@ContentChild(单个)
@ContentChildren(多个)

应用场景

1. 视图查询(View Query)

  • 场景:操作组件自己创建的子元素或子组件。
  • 典型用例
    • 访问模板中的本地变量(如 <input #myInput>)。
    • 调用子组件的方法(如 <app-child #child></app-child>)。
    • 操作DOM元素(如聚焦输入框)。
  • 示例
    @Component({
      template: `<app-child></app-child>`
    })
    export class ParentComponent {
      @ViewChild(ChildComponent) child!: ChildComponent; // 查询自身模板中的ChildComponent
      
      ngAfterViewInit() {
        this.child.doSomething(); // 操作子组件
      }
    }
    

2. 内容查询(Content Query)

  • 场景:操作通过内容投影(<ng-content> 传入的外部内容。
  • 典型用例
    • 构建容器组件(如Tabs、Accordion)。
    • 管理动态投影内容(如卡片头部/尾部定制)。
    • 需要访问父组件提供的子内容(如 <app-card><app-title></app-title></app-card>)。
  • 示例
    @Component({
      selector: 'app-tabs',
      template: `
        <div class="tab-headers">
          <div *ngFor="let tab of tabs">{{ tab.title }}</div>
        </div>
        <ng-content></ng-content> <!-- 投影内容在此 -->
      `
    })
    export class TabsComponent {
      @ContentChildren(TabComponent) tabs!: QueryList<TabComponent>; // 查询投影内容
      
      ngAfterContentInit() {
        console.log("投影的Tab数量:", this.tabs.length);
      }
    }
    
    父组件使用:
    <app-tabs>
      <app-tab title="Tab 1"></app-tab> <!-- 被投影到Tabs内部 -->
      <app-tab title="Tab 2"></app-tab>
    </app-tabs>
    

关键注意事项

  1. 生命周期

    • 视图查询结果在 ngAfterViewInit 后可用。
    • 内容查询结果在 ngAfterContentInit 后可用。
    • 避免在构造函数或 ngOnInit 中访问查询结果(此时结果未初始化)。
  2. 动态内容

    • 使用 QueryList(如 @ViewChildren@ContentChildren 返回的对象)监听动态变化:
      @ContentChildren(TabComponent) tabs!: QueryList<TabComponent>;
      
      ngAfterContentInit() {
        this.tabs.changes.subscribe(() => {
          console.log("Tab数量变化:", this.tabs.length);
        });
      }
      
  3. 跨层级查询

    • 两者默认只查询直接子级
    • 通过设置 descendants: true 查询深层嵌套元素:
      @ViewChildren(ChildComponent, { descendants: true }) deepChildren!: QueryList<ChildComponent>;
      

总结

场景 选择
操作组件内部的子元素/组件 视图查询(@ViewChild
操作父组件投影的内容 内容查询(@ContentChild
需要响应动态增减的元素 QueryList + changes 事件

通过正确区分视图查询和内容查询,可以更精准地控制Angular组件的封装性和复用性,尤其在构建容器型组件(如模态框、卡片、选项卡)时至关重要。

posted @ 2025-07-25 16:23  箫笛  阅读(13)  评论(0)    收藏  举报