美文网首页
14Angular ViewChild和ViewChildren

14Angular ViewChild和ViewChildren

作者: learninginto | 来源:发表于2020-12-26 12:01 被阅读0次
    ViewChild

    用于获取组件模板上的元素

    import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core';
    
    @Component({
      selector: 'app-view-child',
      template: `
          <section>
            <h3>获取dom</h3>
            <div class="box" #box>
              <p>box</p>
            </div>
          </section>
     `,
      styles: []
    })
    export class ViewChildComponent implements OnInit, AfterViewInit {
      @ViewChild('box') private boxEl: ElementRef;
      constructor() {
        // TypeError: Cannot read property 'nativeElement' of undefined
        console.log('0', this.boxEl.nativeElement);
      }
    
      ngOnInit(): void {
        // TypeError: Cannot read property 'nativeElement' of undefined
        console.log('1', this.boxEl.nativeElement);
      }
      ngAfterViewInit(): void {
        console.log('2', this.boxEl.nativeElement); // 正确
      }
    }
    
    

    上面例子中的boxEl,默认在变更检测之后才会获取到元素,所以constructorngOnInit中的console打印为空,而ngAfterViewInit就是在变更检测之后才调用的

    • static

    如果一个元素是静态的,你又想尽早得拿到该元素,可以设置它的static属性为true

    export class ViewChildComponent implements OnInit, AfterViewInit {
      @ViewChild('box', { static: true }) private boxEl: ElementRef;
      constructor() {
        // TypeError: Cannot read property 'nativeElement' of undefined
        console.log('0', this.boxEl.nativeElement);
      }
    
      ngOnInit(): void {
        console.log('1', this.boxEl.nativeElement); // 正确
      }
      ngAfterViewInit(): void {
        console.log(2, this.boxEl.nativeElement); // 正确
      }
    }
    

    建议如果目标从一开始就显示在模版上,即没有被ngIf等指令操控时,就开启static:true

    • 获取子组件(指令)

    获取到组件实例后可以访问子组件到属性和方法

    import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core';
    @Component({
      selector: 'app-view-child-panel',
      templateUrl: './view-child-panel.component.html'
    })
    export class ViewChildPanelComponent implements OnInit {
      readonly name = 'panel';
      constructor() { }
      ngOnInit(): void {}
    }
    
    
    @Component({
      selector: 'app-view-child',
      template: `
          <section>
            <h3>获取自组件</h3>
            <app-view-child-panel></app-view-child-panel>
          </section>
     `,
      styles: []
    })
    export class ViewChildComponent implements OnInit, AfterViewInit {
      @ViewChild(ViewChildPanelComponent, { static: true }) private panel: ViewChildPanelComponent;
        constructor() {}
        ngOnInit(): void {}
        ngAfterViewInit(): void {
          // console.log(2, this.boxEl.nativeElement);
          console.log(this.panel.name);
        }
    }
    
    • 获取子组件(指令) 写法2

    也可以通过模版引用变量获取子组件

    import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core';
    
    @Component({
      selector: 'app-view-child',
      template: `
          <section>
            <h3>获取自组件</h3>
            <app-view-child-panel #myPanel></app-view-child-panel>
          </section>
     `,
      styles: []
    })
    export class ViewChildComponent implements OnInit, AfterViewInit {
      @ViewChild('myPanel', { read: ViewChildPanelComponent, static: true }) private panel: ViewChildPanelComponent;
        constructor() {}
        ngOnInit(): void {}
        ngAfterViewInit(): void {
          // console.log(2, this.boxEl.nativeElement);
          console.log(this.panel.name);
        }
    }
    
    ViewChildren

    与ViewChild类似,不同的是,它可以批量获取模板上相同选择器的元素,并存放到QueryList类中。

    注意:ViewChildren没有static属性

    • 批量获取子组件和dom元素
    import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core';
    
    @Component({
      selector: 'app-view-child',
      template: `
          <section>
            <h3>获取dom</h3>
            <div class="box" #box>
              <p>box</p>
            </div>
          </section>
          
          <section #box>
            <h3>获取子组件</h3>
            <app-view-child-panel #myPanel></app-view-child-panel>
            <app-view-child-panel #myPanel></app-view-child-panel>
            <app-view-child-panel #myPanel></app-view-child-panel>
          </section>
     `,
      styles: []
    })
    export class ViewChildComponent implements OnInit, AfterViewInit {
      @ViewChild('box', { static: true }) private boxEl: ElementRef;
      @ViewChildren('box') private boxEls: QueryList<ElementRef>;
      @ViewChild(ViewChildPanelComponent, { static: true }) private panel: ViewChildPanelComponent;
      @ViewChildren(ViewChildPanelComponent) private panels: QueryList<ViewChildPanelComponent>;    
        constructor() {}
        ngOnInit(): void {}
        ngAfterViewInit(): void {
          console.log(this.panels);
          console.log(this.boxEls);
        }
    }
    
    • QueryList

    模板元素集合

    import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core';
    
    @Component({
      selector: 'app-view-child',
      template: `
          
          <section>
            <h3>获取子组件</h3>
            <button class="btn btn-primary" (click)="showMidPanel = !showMidPanel">toggle mid</button>
            <app-view-child-panel #myPanel></app-view-child-panel>
            <app-view-child-panel #myPanel *ngIf="showMidPanel"></app-view-child-panel>
            <app-view-child-panel #myPanel></app-view-child-panel>
          </section>
     `,
      styles: []
    })
    export class ViewChildComponent implements OnInit, AfterViewInit {
      @ViewChildren(ViewChildPanelComponent) private panels: QueryList<ViewChildPanelComponent>;    constructor() {}
        ngOnInit(): void {}
        ngAfterViewInit(): void {
          this.panels.changes.subscribe(changes => {
            console.log('changes', changes);
          });
        }
    }
    

    相关文章

      网友评论

          本文标题:14Angular ViewChild和ViewChildren

          本文链接:https://www.haomeiwen.com/subject/ijxgnktx.html