【问题标题】:@Viewchild is not working inside Directive, but working in Component@Viewchild 不在指令中工作,而是在组件中工作
【发布时间】:2017-10-27 14:07:39
【问题描述】:

我只是在玩@ViewChild/@ContentChild,我很惊讶地发现@ViewChild 在指令内部不起作用并且对组件工作正常。但在指令中它不起作用。我尝试使用 AfterViewInit 钩子,所以生命周期钩子不是原因。这里还有其他问题,请在下面找到代码。

app.component.html

<div appMain >
  <div #testContentDiv style="background-color: grey">
    <p>This is the first p tag</p>
    <p>This is the second p tag</p> 
  </div>
  <div #testViewDiv style="background-color: yellow">
    <p>This is the first p tag</p>
    <p>This is the second p tag</p>
  </div>
  <app-test-child></app-test-child>
</div>

test-dir.ts --指令

import { Directive, ViewChild, ElementRef, OnInit, AfterViewInit, AfterContentInit, ContentChild } from '@angular/core';

@Directive({
  selector: '[appMain]'
})
export class MainDirective implements OnInit, AfterContentInit, AfterViewInit {

  constructor() { }
  // tslint:disable-next-line:member-ordering
  @ContentChild('testContentDiv') testContent: ElementRef;
  @ViewChild('testViewDiv') testView: ElementRef;
  ngOnInit() {
    //Called after the constructor, initializing input properties, and the first call to ngOnChanges.
    //Add 'implements OnInit' to the class.
    // console.log(this.test.nativeElement);

  }

  ngAfterContentInit() {
    //Called after ngOnInit when the component's or directive's content has been initialized.
    //Add 'implements AfterContentInit' to the class.
    console.log('Content Div: ngAfterContentInit:  ' + this.testContent.nativeElement);
    // console.log('View Div: ngAfterContentInit: ' + this.testView.nativeElement);


  }

  ngAfterViewInit() {
    //Called after ngAfterContentInit when the component's view has been initialized. Applies to components only.
    //Add 'implements AfterViewInit' to the class.
    console.log('Content Div:ngAfterViewInit: ' + this.testContent.nativeElement);
    console.log('View Div: ngAfterViewInit: ' + this.testView.nativeElement);

  }
}

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = "App works";

  constructor() {
  }
}

【问题讨论】:

  • 我正在使用带有 Cli 的 Angular v4.1.3
  • 我很惊讶地发现 @ViewChild 在指令中不起作用 - 指令没有视图/模板,您希望找到什么? @ContentChild 应该可以工作
  • ContentChild 确实有效。但是为什么不 ViewChild 呢?我没有尝试查看任何模板,而是尝试使用已为组件初始化的 ViewChild 引用元素
  • 认为指令是母马元数据/标签...识别/帮助其他东西...只是为了避免混淆..

标签: angular angular2-directives


【解决方案1】:

至少从 Angular v6.x 开始:

根据Angular source code for directives,确实可以选择children。但是,仅使用 @ViewChildren@ContentChildren 装饰器的标准方法似乎对我不起作用。此外,尽管有文档,但我无法让 @ViewChildren 工作。

@ContentChildren,但是,确实对我有用。您需要使用 queries 属性来装饰指令本身(为了清楚起见,此指令已被简化,您仍然需要选择器和其他东西才能使其工作):

@Directive({
  queries: {
    // Give this the same name as your local class property on the directive. "myChildren" in this case
    myChildren: new ContentChildren(YourChild),
  },
})
export class MyDirective implements AfterContentInit {
  // Define the query list as a property here, uninitialized.
  private myChildren: QueryList<YourChild>;

  /**
   * ngAfterContentInit Interface Method
   */
  public ngAfterContentInit() {
    // myChildren is now initialized and ready for use.
  }
}

这对我来说已经足够了,所以我不会浪费更多时间来弄清楚为什么 ViewChildren 不起作用。我对ViewChildrenContentChildren 之间区别的理解是ContentChildren&lt;ng-content&gt; 标签中选择,其中ViewChildren 直接从视图本身中选择。所以,在我看来,这种行为似乎倒退了,但可能是有理由的。

正如预期的那样,ContentChildrenngAfterContentInit 钩子之前不可用,所以不要让那个咬你。

【讨论】:

  • 我也可以通过这种方法获得 ViewChild。谢谢。
  • 更正:您可以使用此方法获取 ContentChildren。它们是不同的。
  • 有时您需要停止命令ng serve 并再次执行此操作。我想它并不总是正确地重新加载。这花了我超过 1 小时
【解决方案2】:

Angular中有三种指令:

组件——带有模板的指令。

结构指令——通过添加和移除 DOM 元素来改变 DOM 布局。

属性指令 — 更改元素、组件或其他指令的外观或行为。

因此,根据定义,组件是唯一带有 template 的指令,因此您可以找到仅用于组件的 @ViewChild

阅读更多关于它的信息here

希望这会有所帮助!

【讨论】:

  • 如果不能在指令中使用,那为什么要编译?而且 ViewChild 文档也没有说它不能使用,这里还有一些我遗漏的东西
  • 我没有尝试查看模板,而是尝试通过 ViewChild 获取对初始化模板的引用,这不应该吗??
  • ViewChild 是带有组件模板的 HTML 元素,ContentChild 是指令标签中的 HTML 元素(例如 &lt;my-dir&gt; &lt;div&gt;hello i am content &lt;/div&gt; &lt;/my-dir&gt; ),因此您可以找到所有指令的内容子但 ViewChild 仅适用于具有模板的组件。
  • 除非您阅读指令的源代码:github.com/angular/angular/blob/6.1.7/packages/core/src/… 它明确指出您可以拥有视图和内容子查询。所以,不,你错了——有办法做到这一点。我还不能让它工作,但当我弄清楚时会发布答案。
  • 很好奇 - 有没有人知道这个?
猜你喜欢
  • 1970-01-01
  • 2015-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-13
  • 2018-01-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多