diff --git a/aio/content/guide/static-query-migration.md b/aio/content/guide/static-query-migration.md index a8e4bd0279..122de0b2c6 100644 --- a/aio/content/guide/static-query-migration.md +++ b/aio/content/guide/static-query-migration.md @@ -1,16 +1,28 @@ # Static Query Migration Guide + +# 静态查询(Static Query)迁移指南 **Important note for library authors: This migration is especially crucial for library authors to facilitate their users upgrading to version 9 when it becomes available (approx Oct 2019).** +**给库作者的重要提示:这份迁移指南对于库作者非常重要,可以方便他们的用户升级到(Angular 的)版本 9(大约在 2019 年 10 月发布)。** + In version 9, the default setting for `@ViewChild` and `@ContentChild` queries is changing in order to fix buggy and surprising behavior in queries (read more about that [here](#what-does-this-flag-mean)). +在版本 9 中,`@ViewChild` 和 `@ContentChild` 这两个查询的默认设置会改变,以修复查询中的 BUG 和意外行为(详情参阅[此处](#what-does-this-flag-mean))。 + In preparation for this change, in version 8, we are migrating all applications and libraries to explicitly specify the resolution strategy for `@ViewChild` and `@ContentChild` queries. +为了应对这个变化,我们要从版本 8 开始就迁移所有应用和库,显式指定 `@ViewChild` 和 `@ContentChild` 查询的解析策略。 + Specifically, this migration adds an explicit "static" flag that dictates when that query's results should be assigned. Adding this flag will ensure your code works the same way when upgrading to version 9. +具体来说,这次迁移会添加一个显式的 “static” 标志,用于指出要何时对该查询的结果进行赋值。等升级到版本 9 的时候,这个标志可以确保这些代码的工作方式都是一样的。 + Before: +之前: + ``` // query results sometimes available in `ngOnInit`, sometimes in `ngAfterViewInit` (based on template) @ViewChild('foo') foo: ElementRef; @@ -18,6 +30,8 @@ Before: After: +之后: + ``` // query results available in ngOnInit @ViewChild('foo', {static: true}) foo: ElementRef; @@ -31,67 +45,111 @@ OR Starting with version 9, the `static` flag will default to false. At that time, any `{static: false}` flags can be safely removed, and we will have a schematic that will update your code for you. +从版本 9 开始,`static` 标志将默认为 false 。那时候,可以安全地删除所有 `{static: false}` 标志,而且我们还会提供一个能帮你更新代码的原理图(schematic)。 + Note: this flag only applies to `@ViewChild` and `@ContentChild` queries specifically, as `@ViewChildren` and `@ContentChildren` queries do not have a concept of static and dynamic (they are always resolved as if they are "dynamic"). +注意:这个标志只适用于 `@ViewChild` 和 `@ContentChild` 这两个查询,因为 `@ViewChildren` 和 `@ContentChildren` 查询没有静态和动态的概念(它们总是“动态”解析)。 + ## FAQ +## 常见问题 + {@a what-to-do-with-todo} ### What should I do if I see a `/* TODO: add static flag */` comment printed by the schematic? +### 在看到由原理图打印的 `/* TODO: add static flag */` 注释时,我该怎么办? + If you see this comment, it means that the schematic couldn't statically figure out the correct flag. In this case, you'll have to add the correct flag based on your application's behavior. For more information on how to choose, see the [next question](#how-do-i-choose). +如果你看到这个注释,就意味着原理图无法自己找到恰当的标志。在这种情况下,你必须根据应用的行为添加正确的标志。要了解如何进行选择,请参阅[下一个问题](#how-do-i-choose) 。 + {@a how-do-i-choose} + ### How do I choose which `static` flag value to use: `true` or `false`? +### 如何选择 `static` 标志:`true` 还是 `false`? + In the official API docs, we have always recommended retrieving query results in [`ngAfterViewInit` for view queries](https://angular.io/api/core/ViewChild#description) and [`ngAfterContentInit` for content queries](https://angular.io/api/core/ContentChild#description). This is because by the time those lifecycle hooks run, change detection has completed for the relevant nodes and we can guarantee that we have collected all the possible query results. +在官方 API 文档中,我们总是建议在[视图查询的 `ngAfterViewInit` 中](https://angular.io/api/core/ViewChild#description) 和[内容查询的 `ngAfterContentInit`](https://angular.io/api/core/ContentChild#description) 中获取查询结果。 +这是因为当这些生命周期钩子运行时,相关节点的变更检测已完成,我们可以确信收集到了所有可能的查询结果。 + Most applications will want to use `{static: false}` for the same reason. This setting will ensure query matches that are dependent on binding resolution (e.g. results inside `*ngIf`s or `*ngFor`s) will be found by the query. +出于同样的原因,大多数应用都希望使用 `{static: false}`。这个设置可以确保找出那些依赖于绑定解析的查询结果(比如 `*ngIf` 或 `*ngFor` 内的查询)。 + There are rarer cases where `{static: true}` flag might be necessary (see [answer here](#should-i-use-static-true)). +在某些很少见情况下,必须使用 `{static: true}` 标志(参见[这里的回答](#should-i-use-static-true))。 + {@a should-i-use-static-true} ### Is there a case where I should use `{static: true}`? +### 什么情况下我应该用 `{static: true}`? + This option was introduced to support creating embedded views on the fly. If you need access to a `TemplateRef` in a query to create a view dynamically, you won't be able to do so in `ngAfterViewInit`. Change detection has already run on that view, so creating a new view with the template will cause an `ExpressionHasChangedAfterChecked` error to be thrown. In this case, you will want to set the `static` flag to `true` and create your view in `ngOnInit`. In most other cases, the best practice is to use `{static: false}`. +这个选项的引入是为了支持动态创建嵌入式视图。如果你要查询到一个 `TemplateRef` 来动态创建一个视图,就无法在 `ngAfterViewInit` 中这样做。变量检测已在该视图上运行过,因此这时候使用该模板创建一个新视图就会抛出 `ExpressionHasChangedAfterChecked` 错误。在这种情况下,你要把 `static` 标志设置为 `true`,并在 `ngOnInit` 中创建你的视图。在大多数其他情况下,最好的做法是使用 `{static: false}`。 + However, to facilitate the migration to version 8, you may also want to set the `static` flag to `true` if your component code already depends on the query results being available some time **before** `ngAfterViewInit` (for view queries) or `ngAfterContentInit` (for content queries). For example, if your component relies on the query results being populated in the `ngOnInit` hook or in `@Input` setters, you will need to either set the flag to `true` or re-work your component to adjust to later timing. +为了便于迁移到版本 8 中,如果你的组件代码中期望这些查询结果在 `ngAfterViewInit`(对于视图查询)或 `ngAfterContentInit`(对于内容查询)**之前**的某个时刻就绪,可能也要把 `static` 标志设置为 `true`。例如,如果你的组件期望在 `ngOnInit` 钩子或 `@Input` 的 setter 中这些查询结果已经就绪,就要把该标志设置为 `true` 或者改写你的组件以推迟它的执行时间。 + Note: Selecting the static option means that query results nested in `*ngIf` or `*ngFor` will not be found by the query. These results are only retrievable after change detection runs. +注意:把 `static` 设置为 true 意味着嵌在 `*ngIf` 或 `*ngFor` 中的查询结果将不会被此查询发现。这些结果只有在运行过变更检测之后才能获取。 + {@a what-does-this-flag-mean} ### What does this flag mean and why is it necessary? +### 这个标志是什么意思,它有什么必要? + The default behavior for queries has historically been undocumented and confusing, and has also commonly led to issues that are difficult to debug. In version 9, we would like to make query behavior more consistent and simple to understand. +以前,查询的默认行为一直没有文档记载,这会令人困惑,而且也常导致难以调试的问题。在版本 9 中,我们希望这种查询行为更加一致,更易于理解。 + To explain why, first it's important to understand how queries have worked up until now. +为了解释个中原由,首先要弄清楚到目前为止这些查询是如何工作的。 + Without the `static` flag, the compiler decided when each query would be resolved on a case-by-case basis. All `@ViewChild`/`@ContentChild` queries were categorized into one of two buckets at compile time: "static" or "dynamic". This classification determined when query results would become available to users. +当没有 `static` 标志时,编译器会自行决定每个查询应该如何解析。所有的 `@ViewChild` / `@ContentChild` 查询在编译时都会被归类为两种方式之一:“static” 或 “dynamic”。当查询结果可供用户使用时,就会确定该使用哪种方式。 + - **Static queries** were queries where the result could be determined statically because the result didn't depend on runtime values like bindings. Results from queries classified as static were available before change detection ran for that view (accessible in `ngOnInit`). + **静态查询**的查询结果是可以静态确定的,因为其结果并不依赖运行时的值(比如绑定)。静态查询的结果在该视图的变更检测运行之前就是可用的(可以在`ngOnInit`访问)。 + - **Dynamic queries** were queries where the result could NOT be determined statically because the result depended on runtime values (aka bindings). Results from queries classified as dynamic were not available until after change detection ran for that view (accessible in `ngAfterContentInit` for content queries or `ngAfterViewInit` for view queries). + **动态查询**是那些无法静态确定结果的查询,因为其结果取决于运行时的值(也就是绑定)。动态查询的结果在运行该视图的变更检测之前是不可用的(只能在 `ngAfterContentInit` 中访问内容查询或在 `ngAfterViewInit` 中访问视图查询)。 + For example, let's say we have a component, `Comp`. Inside it, we have this query: +例如,假设我们有一个组件 `Comp` 。在其中,我们有这样一个查询: + ``` @ViewChild(Foo) foo: Foo; ``` and this template: +和这样的模板: + ```
``` @@ -100,8 +158,12 @@ This `Foo` query would be categorized as static because at compile-time it's kno Because the query result is not dependent on runtime values, we don't have to wait for change detection to run on the template before resolving the query. Consequently, results can be made available in `ngOnInit`. +这个 `Foo` 查询会被归类为静态查询,这是因为在编译时,就已经知道 `