ChatGPT解决这个技术问题 Extra ChatGPT

我应该如何在 Angular 8 中为 @ViewChild 使用新的静态选项?

我应该如何配置新的 Angular 8 view child?

@ViewChild('searchText', {read: ElementRef, static: false})
public searchTextInput: ElementRef;

对比

@ViewChild('searchText', {read: ElementRef, static: true})
public searchTextInput: ElementRef;

哪个更好?我什么时候应该使用 static:truestatic:false


P
Poul Kruijt

在大多数情况下,您需要使用 {static: false}。像这样设置它可以确保找到依赖于绑定解析的查询匹配(如结构指令 *ngIf, etc...)。

何时使用 static: false 的示例:

@Component({
  template: `
    <div *ngIf="showMe" #viewMe>Am I here?</div>
    <button (click)="showMe = !showMe"></button>
  ` 
})
export class ExampleComponent {
  @ViewChild('viewMe', { static: false })
  viewMe?: ElementRef<HTMLElement>; 

  showMe = false;
}

static: false 将成为 Angular 9 中的默认后备行为。阅读更多herehere

引入了 { static: true } 选项以支持动态创建嵌入式视图。当您动态创建视图并想要访问 TemplateRef 时,您将无法在 ngAfterViewInit 中这样做,因为它会导致 ExpressionHasChangedAfterChecked 错误。将静态标志设置为 true 将在 ngOnInit 中创建您的视图。

尽管如此:

在大多数其他情况下,最佳实践是使用 {static: false}。

请注意,尽管 { static: false } 选项将在 Angular 9 中设为默认值。这意味着不再需要设置静态标志,除非您想使用 static: true 选项。

您可以使用 angular cli ng update 命令自动升级您当前的代码库。

如需迁移指南和更多相关信息,您可以查看 herehere

#静态查询和动态查询有什么区别? @ViewChild() 和 @ContentChild() 查询的静态选项确定查询结果何时可用。

使用静态查询 (static: true),一旦创建了视图,查询就会解析,但在更改检测运行之前。但是,结果永远不会更新以反映视图的更改,例如对 ngIf 和 ngFor 块的更改。

对于动态查询(静态:false),查询分别在 @ViewChild() 和 @ContentChild() 的 ngAfterViewInit() 或 ngAfterContentInit() 之后解析。结果将根据您的视图的更改进行更新,例如对 ngIf 和 ngFor 块的更改。

使用 static: true 的一个很好的用例是,如果您使用 fromEvent 绑定到模板中定义的元素。考虑以下模板:

<div [ngStyle]="thumbStyle$ | async" #thumb></div>

然后,您可以处理此元素上的事件,而无需使用订阅或初始化挂钩(如果您不想或不能使用角度事件绑定):

@Component({})
export class ThumbComponent {
  @ViewChild('thumb', { static: true })
  thumb?: ElementRef<HTMLElement>;

  readonly thumbStyle$ = defer(() => fromEvent(this.thumb, 'pointerdown').pipe(
    switchMap((startEvent) => fromEvent(document, 'pointermove', { passive: true })
    // transform to proper positioning
  ));
}

使用 defer 很重要。这将确保 observable 仅在订阅时才被解析。这将在 ngAfterViewInit 被触发之前发生,此时 async 管道订阅它。因为我们使用的是 static: true,所以 this.thumb 已填充。


请更新 Angular 文档的链接(发布后更改)angular.io/api/core/ViewChild#description
我无法访问 childView 的实例。它一直说未定义。
您能否提供有关在 Angular 9 中删除静态选项的信息的链接?
@AlexMarinov我已经更新了我的答案,以更清楚地说明 Angular 9 中会发生什么。关于这个的链接在迁移指南中
@MinhNghĩa 如果您将整个组件嵌套在组件模板之外,则可以使用 { static: true },但如果不需要直接访问 ngOnInit 内的 ViewChild,您应该只使用 { static: false }
d
dave0688

因此,根据经验,您可以选择以下内容:

{ static: true } 需要在 ngOnInit 中访问 ViewChild 时设置。

{ static: false } 只能在 ngAfterViewInit 中访问。当您在模板中的元素上有一个结构指令(即 *ngIf)时,这也是您想要的。


注意:在 Angular 9 中,静态标志默认为 false,因此“可以安全地删除任何 {static: false} 标志”。文档:angular.io/guide/static-query-migration
S
Sachin Gupta

从角度 docs

static - 是否在更改检测运行之前解析查询结果(即仅返回静态结果)。如果未提供此选项,编译器将退回到其默认行为,即使用查询结果来确定查询解析的时间。如果任何查询结果在嵌套视图中(例如 *ngIf),则查询将在更改检测运行后解析。否则,它将在更改检测运行之前解决。

如果孩子不依赖任何条件,则使用 static:true 可能是一个更好的主意。如果元素的可见性发生变化,则 static:false 可能会产生更好的结果。

PS:由于它是一项新功能,我们可能需要运行性能基准测试。

编辑

正如@Massimiliano Sartoretto 所提到的,github commit 可能会为您提供更多见解。


我将添加此功能背后的官方动机 github.com/angular/angular/pull/28810
c
corolla

来到这里是因为在升级到 Angular 8 后, ngOnInit 中的 ViewChild 为空。

静态查询在 ngOnInit 之前填充,而动态查询(静态:false)在之后填充。换句话说,如果在你设置 static:false 之后 viewchild 现在在 ngOnInit 中为 null,你应该考虑更改为 static:true 或将代码移动到 ngAfterViewInit。

请参阅https://github.com/angular/angular/blob/master/packages/core/src/view/view.ts#L332-L336

其他答案是正确的,并解释了为什么会出现这种情况:依赖于结构指令的查询,例如 ngIf 中的 ViewChild 引用,应该在该指令的条件已解决之后运行,即在更改检测之后。但是,可以安全地使用 static: true ,从而在 ngOnInit 之前解析未嵌套引用的查询。恕我直言,这个特殊情况值得一提,因为空异常可能是您遇到这种特殊性的第一种方式,就像对我一样。


S
Samar Abdallah

查看子 @angular 5+ 标记两个参数('本地引用名称',静态:false|true)

@ViewChild('nameInput', { static: false }) nameInputRef: ElementRef;

要知道真假之间的区别检查这个

static - 是否在更改检测运行之前解析查询结果(即仅返回静态结果)。如果未提供此选项,编译器将退回到其默认行为,即使用查询结果来确定查询解析的时间。如果任何查询结果在嵌套视图中(例如 *ngIf),则查询将在更改检测运行后解析。否则,它将在更改检测运行之前解决。


T
Tethys Zhang

在 ng8 中,您可以手动设置何时访问父组件中的子组件。当你设置 static 为 true 时,意味着父组件只能在 onInit 钩子中获取组件的定义:例如:

 // You got a childComponent which has a ngIf/for tag
ngOnInit(){
  console.log(this.childComponent);
}

ngAfterViewInit(){
  console.log(this.childComponent);
}

如果 static 为 false ,那么您只能在 ngAfterViewInit() 中获得定义,在 ngOnInit() 中,您将获得未定义。


J
JMP

查看孩子

...可以将其用于模板元素引用。

...对于特定组件参考之外。

使用装饰器样式语法.. @ViewChild( selector) reference : ElementRef || QueryList.

特定组件或元素的引用。

AfterViewInIt() 中使用它。

我们可以在 Oninit() 中使用它。

但这对于特定使用ngAfterViewInit()

最后 {static : false} 应放在 @ViewChild( Useme , { static : false})... 中以供模板变量引用。

模板文件中的变量看起来像。 #Useme


P
Pavan

静态属性告知 Angular 我们孩子的可用性

例如:如果 static 设置为 true,我们将通知 Angular 我们的孩子从一开始就在页面上可用(这意味着它不依赖于 *ngIf、页面绑定、API 调用等),因此 Angular 在最早的生命周期中查找它钩子(ngOnInit)并且不再寻找它

如果我们将 static 设置为 false ,我们会通知 angular 我们的孩子依赖于一些条件指令,因此 angular 会在每个更改检测周期后尝试寻找我们的孩子,如果它可用,我们可以在 ngAfterViewInit() 生命周期钩子中访问它


正好相反:{static: true} Angular 只检查一次(在组件的早期阶段——这就是你可以在 ngOnInit 中获取它的原因——)并且元素不能在 *ngIf 下,等等。

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅