开发指南-管道 初译即将完成
This commit is contained in:
parent
c3c1fc6627
commit
88a86ff4a0
|
@ -5,33 +5,55 @@ block includes
|
|||
Every application starts out with what seems like a simple task: get data, transform them, and show them to users.
|
||||
Getting data could be as simple as creating a local variable or as complex as streaming data over a Websocket.
|
||||
|
||||
每个应用开始的时候差不多都是一些简单任务:获取数据、转换它们,然后把它们显示给用户。
|
||||
获取数据可能简单到创建一个局部变量就行,也可能复杂到从WebSocket中获取数据流。
|
||||
|
||||
Once data arrive, we could push their raw `toString` values directly to the view.
|
||||
That rarely makes for a good user experience.
|
||||
E.g., almost everyone prefers a simple birthday date like
|
||||
<samp>April 15, 1988</samp> to the original raw string format
|
||||
— <samp>Fri Apr 15 1988 00:00:00 GMT-0700 (Pacific Daylight Time)</samp>.
|
||||
|
||||
一旦取到数据,我们可以把它们原始值的`toString`结果直接推入视图中。
|
||||
但这种做法很少能具备良好的用户体验。
|
||||
比如,几乎每个人都更喜欢简单的日期格式,例如<samp>1988-04-15</samp>,而不是服务端传过来的原始字符串格
|
||||
式 —— <samp>Fri Apr 15 1988 00:00:00 GMT-0700 (Pacific Daylight Time)</samp>。
|
||||
|
||||
Clearly some values benefit from a bit of massage. We soon discover that we
|
||||
desire many of the same transformations repeatedly, both within and across many applications.
|
||||
We almost think of them as styles.
|
||||
In fact, we'd like to apply them in our HTML templates as we do styles.
|
||||
|
||||
显然,对某些值做一点修饰会显得更友好。我们很快就会发现,相同的“数据转换”工作要重复做很多次,甚至会出现在很多应用中。
|
||||
我们甚至可以把它看做样式。
|
||||
事实上,我们确实更喜欢像样式那样把它们应用到HTML模板中。
|
||||
p.
|
||||
Welcome, Angular pipes, the simple display-value transformations that we can declare in our HTML!
|
||||
Try the #[+liveExampleLink2()].
|
||||
|
||||
p.
|
||||
欢迎来到Angular“管道(Pipe)”的世界!我们可以把这种简单的“显示值”转换器声明在HTML中。
|
||||
试试#[+liveExampleLink2('在线例子')].
|
||||
|
||||
.l-main-section
|
||||
:marked
|
||||
## Using Pipes
|
||||
## 使用管道
|
||||
|
||||
A pipe takes in data as input and transforms it to a desired output.
|
||||
We'll illustrate by transforming a component's birthday property into
|
||||
a human-friendly date:
|
||||
|
||||
管道把数据作为输入,然后转换它,给出期望的输出。
|
||||
我们将把组件的`birthday`属性转换成对人类更友好的日期格式,来说明这一点:
|
||||
|
||||
+makeExample('pipes/ts/app/hero-birthday1.component.ts', null, 'app/hero-birthday1.component.ts')(format='.')
|
||||
|
||||
:marked
|
||||
Focus on the component's template.
|
||||
|
||||
重点看下组件的模板。
|
||||
|
||||
+makeExample('pipes/ts/app/app.component.html', 'hero-birthday-template')(format=".")
|
||||
|
||||
:marked
|
||||
|
@ -39,31 +61,50 @@ p.
|
|||
[pipe operator](./template-syntax.html#pipe) ( | ) to the [Date pipe](../api/common/DatePipe-class.html)
|
||||
function on the right. All pipes work this way.
|
||||
|
||||
在这个插值表达式中,我们让组件的`birthday`值通过[管道操作符](./template-syntax.html#pipe)( | )流动到
|
||||
右侧的[Date管道](../api/common/DatePipe-class.html)函数中。所有管道都会用这种方式工作。
|
||||
|
||||
.l-main-section
|
||||
:marked
|
||||
## Built-in pipes
|
||||
## 内建的管道
|
||||
Angular comes with a stock of pipes such as
|
||||
`DatePipe`, `UpperCasePipe`, `LowerCasePipe`, `CurrencyPipe`, and `PercentPipe`.
|
||||
They are all immediately available for use in any template.
|
||||
|
||||
Angular内置了一些管道,比如`DatePipe`、`UpperCasePipe`、`LowerCasePipe`、`CurrencyPipe`和`PercentPipe`。
|
||||
它们全都可以直接用在任何模板中。
|
||||
|
||||
.l-sub-section
|
||||
:marked
|
||||
Learn more about these and many other built-in pipes in the the [API Reference](../api/#!?apiFilter=pipe);
|
||||
filter for entries that include the word "pipe".
|
||||
|
||||
要学习更多内建管道的知识,参见[API参考](../api/#!?apiFilter=pipe),并用“pipe”为关键词对结果进行过滤。
|
||||
|
||||
Angular 2 doesn't have a `FilterPipe` or an `OrderByPipe` for reasons explained in an [appendix below](#no-filter-pipe).
|
||||
|
||||
Angular 2没有`FilterPipe`或`OrderByPipe`管道,原因在[后面的附录中](#no-filter-pipe)有解释。
|
||||
|
||||
.l-main-section
|
||||
:marked
|
||||
## Parameterizing a Pipe
|
||||
## 对管道进行参数化
|
||||
|
||||
A pipe may accept any number of optional parameters to fine-tune its output.
|
||||
We add parameters to a pipe by following the pipe name with a colon ( : ) and then the parameter value
|
||||
(e.g., `currency:'EUR'`). If our pipe accepts multiple parameters, we separate the values with colons (e.g. `slice:1:5`)
|
||||
|
||||
管道可能接受任何数量的可选参数来对它的输出进行微调。
|
||||
我们可以在管道名后面添加一个冒号( : )再跟一个参数值,来为管道添加参数(比如`currency:'EUR'`)。
|
||||
如果我们的管道可以接受多个参数,那么就用冒号来分隔这些参数值(比如`slice:1:5`)。
|
||||
|
||||
We'll modify our birthday template to give the date pipe a format parameter.
|
||||
After formatting the hero's April 15th birthday, it should render as **<samp>04/15/88</samp>**.
|
||||
|
||||
我们将通过修改生日模板来给这个日期管道提供一个格式化参数。
|
||||
当格式化完该英雄的4月15日生日之后,它应该被渲染成**<samp>04/15/88</samp>**。
|
||||
|
||||
+makeExample('pipes/ts/app/app.component.html', 'format-birthday')(format=".")
|
||||
|
||||
:marked
|
||||
|
@ -72,9 +113,14 @@ p.
|
|||
such as a string literal or a component property.
|
||||
In other words, we can control the format through a binding the same way we control the birthday value through a binding.
|
||||
|
||||
参数值可以是任何有效的[模板表达式](./template-syntax.html#template-expressions),比如字符串字面量或组件的属性。
|
||||
换句话说,借助属性绑定,我们也可以像用绑定来控制生日的值一样,控制生日的显示格式。
|
||||
|
||||
Let's write a second component that *binds* the pipe's format parameter
|
||||
to the component's `format` property. Here's the template for that component:
|
||||
|
||||
我们来写第二个组件,它把管道的格式参数*绑定*到该组件的`format`属性。这里是新组件的模板:
|
||||
|
||||
+makeExample('pipes/ts/app/hero-birthday2.component.ts', 'template', 'app/hero-birthday2.component.ts (template)')(format=".")
|
||||
|
||||
:marked
|
||||
|
@ -82,6 +128,9 @@ p.
|
|||
That method toggles the component's `format` property between a short form
|
||||
(`'shortDate'`) and a longer form (`'fullDate'`).
|
||||
|
||||
我们还能把一个按钮添加到模板中,并把它的点击事件绑定到组件的`toggleFormat()`方法。
|
||||
此方法会在短日期格式(`'shortDate'`)和长日期格式(`'fullDate'`)之间切换组件的`format`属性。
|
||||
|
||||
+makeExample('pipes/ts/app/hero-birthday2.component.ts', 'class', 'app/hero-birthday2.component.ts (class)')(format='.')
|
||||
|
||||
:marked
|
||||
|
@ -89,6 +138,8 @@ p.
|
|||
"**<samp>04/15/1988</samp>**" and
|
||||
"**<samp>Friday, April 15, 1988</samp>**".
|
||||
|
||||
当我们点击按钮的时候,显示的日志会在"**<samp>04/15/1988</samp>**"和"**<samp>Friday, April 15, 1988</samp>**"之间切换。
|
||||
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/pipes/date-format-toggle-anim.gif' alt="Date Format Toggle")
|
||||
:marked
|
||||
|
@ -97,88 +148,139 @@ figure.image-display
|
|||
:marked
|
||||
Learn more about the `DatePipes` format options in the [API Docs](../api/common/DatePipe-class.html).
|
||||
|
||||
要了解更多`DatePipes`的格式选项,请参阅[API文档](../api/common/DatePipe-class.html)。
|
||||
|
||||
:marked
|
||||
## Chaining pipes
|
||||
## 链式管道
|
||||
|
||||
We can chain pipes together in potentially useful combinations.
|
||||
In the following example, we chain the birthday to the `DatePipe` and on to the `UpperCasePipe`
|
||||
so we can display the birthday in uppercase. The following birthday displays as
|
||||
**<samp>APR 15, 1988</samp>**
|
||||
|
||||
我们可以把管道链在一起,以组合出一些潜在的有用功能。
|
||||
下面这个例子中,我们把`birthday`链到`DatePipe`管道,然后又链到`UpperCasePipe`,这样我们就可以把生日显示成大写形式了。
|
||||
比如下面的代码就会把生日显示成**<samp>APR 15, 1988</samp>**:
|
||||
|
||||
+makeExample('pipes/ts/app/app.component.html', 'chained-birthday')(format=".")
|
||||
|
||||
:marked
|
||||
This example — which displays **<samp>FRIDAY, APRIL 15, 1988</samp>** —
|
||||
chains the same pipes as above, but passes in a parameter to `date` as well.
|
||||
|
||||
下面这个显示**<samp>FRIDAY, APRIL 15, 1988</samp>**的例子用同样的方式链接了这两个管道,而且同时还给`date`管道传进去一个参数。
|
||||
|
||||
+makeExample('pipes/ts/app/app.component.html', 'chained-parameter-birthday')(format=".")
|
||||
|
||||
.l-main-section
|
||||
:marked
|
||||
## Custom Pipes
|
||||
## 自定义管道
|
||||
|
||||
We can write our own custom pipes.
|
||||
Here's a custom pipe named `ExponentialStrengthPipe` that can boost a hero's powers:
|
||||
|
||||
我们还可以写自己的自定义管道。
|
||||
下面就是一个名叫`ExponentialStrengthPipe`的管道,它可以放大英雄的能力:
|
||||
|
||||
+makeExample('pipes/ts/app/exponential-strength.pipe.ts', null, 'app/exponential-strength.pipe.ts')(format=".")
|
||||
|
||||
:marked
|
||||
This pipe definition reveals several key points
|
||||
|
||||
在这个管道的定义中体现了几个关键点:
|
||||
|
||||
* A pipe is a class decorated with pipe metadata.
|
||||
|
||||
* 管道是一个带有“管道元数据(pipe metadata)”装饰器的类。
|
||||
|
||||
* The pipe class implements the `PipeTransform` interface's `transform` method that
|
||||
accepts an input value followed by optional parameters and returns the transformed value.
|
||||
|
||||
* 这个管道类实现了`PipeTransform`接口的`transform`方法,该方法接受一个输入值和一些可选参数,并返回转换后的值。
|
||||
|
||||
* There will be one additional argument to the `transform` method for each parameter passed to the pipe.
|
||||
Our pipe has one such parameter: the `exponent`.
|
||||
|
||||
* 当每个输入值被传给`transform`方法时,还会带有一个额外的参数,比如我们这个管道中的`exponent`(放大指数)。
|
||||
|
||||
* We tell Angular that this is a pipe by applying the
|
||||
`@Pipe` #{_decorator} which we import from the core Angular library.
|
||||
|
||||
* 我们通过`@Pipe`#{_decoratorCn}告诉Angular:这是一个管道。该#{_decoratorCn}是从Angular的`core`库中引入的。
|
||||
|
||||
* The `@Pipe` #{_decorator} allows us to define the
|
||||
pipe name that we'll use within template expressions. It must be a valid JavaScript identifier.
|
||||
Our pipe's name is `exponentialStrength`.
|
||||
|
||||
* 这个`@Pipe`#{_decoratorCn}允许我们定义管道的名字,这个名字会被用在模板表达式中。它必须是一个有效的JavaScript标识符。
|
||||
比如,我们这个管道的名字是`exponentialStrength`。
|
||||
|
||||
.l-sub-section
|
||||
:marked
|
||||
### The *PipeTransform* Interface
|
||||
### *PipeTransform*接口
|
||||
|
||||
The `transform` method is essential to a pipe.
|
||||
The `PipeTransform` *interface* defines that method and guides both tooling and the compiler.
|
||||
It is technically optional; Angular looks for and executes the `transform` method regardless.
|
||||
|
||||
`transform`方法是管道的基本要素。
|
||||
`PipeTransform`*接口*中定义了它,并用它指导各种工具和编译器。
|
||||
从技术角度看,它是可选的。Angular不会管它,而是直接查找并执行`transform`方法。
|
||||
|
||||
:marked
|
||||
Now we need a component to demonstrate our pipe.
|
||||
|
||||
现在,我们需要一个组件来演示这个管道。
|
||||
+makeExample('pipes/ts/app/power-booster.component.ts',null,'app/power-booster.component.ts')(format='.')
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/pipes/power-booster.png' alt="Power Booster")
|
||||
|
||||
:marked
|
||||
Two things to note:
|
||||
|
||||
要注意的有两点:
|
||||
1. We use our custom pipe the same way we use the built-in pipes.
|
||||
|
||||
1. 我们使用自定义管道的方式和内建管道完全相同。
|
||||
|
||||
1. We must include our pipe in the `pipes` #{_array} of the `@Component` #{_decorator}.
|
||||
|
||||
1. 我们必须在`@Component`#{_decoratorCn}的`pipes`数组中包含这个管道。
|
||||
|
||||
.callout.is-helpful
|
||||
header Remember the pipes #{_array}!
|
||||
header 记住`pipes`数组
|
||||
:marked
|
||||
Angular reports an error if we neglect to list our custom pipe.
|
||||
We didn't list the `DatePipe` in our previous example because all
|
||||
Angular built-in pipes are pre-registered.
|
||||
Custom pipes must be registered manually.
|
||||
|
||||
如果我们忘了列出自定义管道,Angular会报告一个错误。
|
||||
我们不用在以前的例子中列出`DatePipe`,是因为所有的Angular内建管道都被预先注册过了。
|
||||
而自定义管道就必须被手动注册。
|
||||
|
||||
p.
|
||||
If we try the #[+liveExampleLink()],
|
||||
we can probe its behavior by changing the value and the optional exponent in the template.
|
||||
|
||||
p.
|
||||
试试这个#[+liveExampleLink()],然后在模板中修改能量值和可选的放大指数,就能看懂它的行为方式。
|
||||
|
||||
:marked
|
||||
## Power Boost Calculator (extra-credit)
|
||||
## 能力倍增计算器(加分项)
|
||||
|
||||
It's not much fun updating the template to test our custom pipe.
|
||||
We could upgrade the example to a "Power Boost Calculator" that combines
|
||||
our pipe and two-way data binding with `ngModel`.
|
||||
|
||||
仅仅升级模板来测试这个自定义管道其实没多大意思。
|
||||
我们干脆把这个例子升级为“能力倍增计算器”,它可以把该管道和使用`ngModel`的双向数据绑定组合起来。
|
||||
|
||||
+makeExample('pipes/ts/app/power-boost-calculator.component.ts', null, '/app/power-boost-calculator.component.ts')(format='.')
|
||||
|
||||
figure.image-display
|
||||
|
@ -188,22 +290,34 @@ figure.image-display
|
|||
a#change-detection
|
||||
:marked
|
||||
## Pipes and Change Detection
|
||||
## 管道与变更检测
|
||||
|
||||
Angular looks for changes to data-bound values through a *change detection* process that runs after every JavaScript event:
|
||||
every keystroke, mouse move, timer tick, and server response. This could be expensive.
|
||||
Angular strives to lower the cost whenever possible and appropriate.
|
||||
|
||||
Angular通过*变更检测*过程来查找绑定值的更改,并在每一次JavaScript事件之后运行:每次按键、鼠标移动、定时器以及服务器的响应。
|
||||
这可能会让变更检测显得很昂贵,但是Angular会尽可能降低变更检测的成本。
|
||||
|
||||
Angular picks a simpler, faster change detection algorithm when we use a pipe. Let's see how.
|
||||
|
||||
当我们使用管道时,Angular选用了一种简单、快速的变更检测算法。
|
||||
|
||||
### No pipe
|
||||
### 无管道
|
||||
|
||||
The component in our next example uses the default, aggressive change detection strategy to monitor and update
|
||||
its display of every hero in the `heroes` #{_array}. Here's the template:
|
||||
|
||||
我们下一个例子中的组件使用默认的、激进(昂贵)的变更检测策略来检测和更新`heroes`数组中的每个英雄。下面是它的模板:
|
||||
|
||||
+makeExample('pipes/ts/app/flying-heroes.component.html', 'template-1', 'app/flying-heroes.component.html (v1)')(format='.')
|
||||
|
||||
:marked
|
||||
The companion component class provides heroes, adds new heroes into the #{_array}, and can reset the #{_array}.
|
||||
|
||||
和模板相伴的组件类可以提供英雄数组,能把新的英雄添加到数组中,还能重置英雄数组。
|
||||
|
||||
+makeExample('pipes/ts/app/flying-heroes.component.ts', 'v1', 'app/flying-heroes.component.ts (v1)')(format='.')
|
||||
|
||||
:marked
|
||||
|
@ -211,36 +325,68 @@ a#change-detection
|
|||
The `reset` button replaces `heroes` with a new #{_array} of the original heroes and Angular updates the display when we do.
|
||||
If we added the ability to remove or change a hero, Angular would detect those changes too and update the display as well.
|
||||
|
||||
我们可以添加新的英雄,加完之后,Angular就会更新显示。
|
||||
`reset`按钮会把`heroes`替换成一个由原来的英雄组成的新数组,重置完之后,Angular就会更新显示。
|
||||
如果我们提供了删除或修改英雄的能力,Angular也会检测到那些更改,并更新显示。
|
||||
|
||||
### Flying Heroes pipe
|
||||
### “会飞的英雄”管道
|
||||
|
||||
Let's add a `FlyingHeroesPipe` to the `*ngFor` repeater that filters the list of heroes to just those heroes who can fly.
|
||||
|
||||
我们来往`*ngFor`重复器中添加一个`FlyingHeroesPipe`管道,这个管道能过滤出所有会飞的英雄。
|
||||
|
||||
+makeExample('pipes/ts/app/flying-heroes.component.html', 'template-flying-heroes', 'app/flying-heroes.component.html (flyers)')(format='.')
|
||||
:marked
|
||||
Here's the `FlyingHeroesPipe` implementation which follows the pattern for custom pipes we saw earlier.
|
||||
|
||||
下面是`FlyingHeroesPipe`的实现,它遵循了我们以前见过的那些写自定义管道的模式。
|
||||
|
||||
+makeExample('pipes/ts/app/flying-heroes.pipe.ts', 'pure', 'app/flying-heroes.pipe.ts')(format='.')
|
||||
|
||||
p.
|
||||
When we run the sample now we see odd behavior (try it in the #[+liveExampleLink()]).
|
||||
Every hero we add is a flying hero but none of them are displayed.
|
||||
|
||||
p.
|
||||
如果我们现在就运行这个例子,我们会看到一些古怪的行为(在#[+liveExampleLink()]中试试)。
|
||||
我们添加的每个英雄都会飞,但他们一个都没有显示出来。
|
||||
|
||||
:marked
|
||||
Although we're not getting the behavior we want, Angular isn't broken.
|
||||
It's just using a different change detection algorithm — one that ignores changes to the list or any of its items.
|
||||
|
||||
虽然我们没有得到期望的行为,但Angular也没有出错。
|
||||
这里只是用了另一种变更检测算法 —— 它会忽略对列表及其子项所做的任何更改。
|
||||
|
||||
Look at how we're adding a new hero:
|
||||
|
||||
来看看我们是如何添加新英雄的:
|
||||
|
||||
+makeExample('pipes/ts/app/flying-heroes.component.ts', 'push')(format='.')
|
||||
:marked
|
||||
We're adding the new hero into the `heroes` #{_array}. The reference to the #{_array} hasn't changed.
|
||||
It's the same #{_array}. That's all Angular cares about. From its perspective, *same #{_array}, no change, no display update*.
|
||||
|
||||
当我们往`heroes`数组中添加一个新的英雄时,这个数组的引用并没有改变。它还是那个数组。而引用却是Angular所关心的一切。
|
||||
从Angular的角度来看,*这是同一个数组,没有变化,也就不需要更新显示*。
|
||||
|
||||
We can fix that. Let's create a new #{_array} with the new hero appended and assign that to `heroes`.
|
||||
This time Angular detects that the #{_array} reference has changed.
|
||||
It executes the pipe and updates the display with the new #{_array} which includes the new flying hero.
|
||||
|
||||
我们可以修复它。让我们创建一个新数组,把这个英雄追加进去,并把它赋给`heroes`。
|
||||
这次,Angular检测到数组的引用变化了。它执行了这个管道,并使用这个新数组更新显示,这次它就包括新的飞行英雄了。
|
||||
|
||||
*If we **mutate** the #{_array}, no pipe is invoked and no display updated;
|
||||
if we **replace** the #{_array}, then the pipe executes and the display is updated*.
|
||||
The *Flying Heroes* extends the
|
||||
code with checkbox switches and additional displays to help us experience these effects.
|
||||
|
||||
*如果我们**修改了**这个数组,不会执行任何管道,显示也没有更新。
|
||||
如果我们**替换了**这个数组,管道就会被执行,显示也更新了。*
|
||||
这个*飞行英雄*的例子用检查框和额外的显示内容扩展了原有代码,来帮我们体验这些效果。
|
||||
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/pipes/flying-heroes-anim.gif' alt="Flying Heroes")
|
||||
|
||||
|
@ -250,6 +396,10 @@ figure.image-display
|
|||
That's an easy rule to follow in *this toy* example
|
||||
where the only way to change the data is by adding a new hero.
|
||||
|
||||
直接替换这个数组是通知Angular更新显示的一种高效方式。
|
||||
我们该什么时候替换这个数组呢?当数据变化的时候。
|
||||
在这个*玩具级*例子中,这是一个简单的规则,因为这里修改数据的唯一途径就是添加新英雄。
|
||||
|
||||
More often we don't know when the data have changed,
|
||||
especially in applications that mutate data in many ways,
|
||||
perhaps in application locations far away.
|
||||
|
@ -258,23 +408,37 @@ figure.image-display
|
|||
We strive as much as possible to keep the component class independent of the HTML.
|
||||
The component should be unaware of pipes.
|
||||
|
||||
更多情况下,我们不知道什么时候数据变化了,尤其是在那些有很多种途径改动数据的程序中 —— 可能在程序中很远的地方。
|
||||
组件就是一个通常无法知道那些改动的例子。此外,它会导致削足适履 —— 扭曲我们的组件设计来适应管道。
|
||||
我们要尽可能保持组件类独立于HTML。组件不应该关心管道的存在。
|
||||
|
||||
Perhaps we should consider a different kind of pipe for filtering flying heroes, an *impure pipe*.
|
||||
|
||||
也行我们可以考虑用另一种管道来过滤会飞的英雄了,一个*非纯(impure)管道*。
|
||||
|
||||
.l-main-section
|
||||
:marked
|
||||
## Pure and Impure Pipes
|
||||
## 纯(pure)管道与非纯(impure)管道
|
||||
|
||||
There are two categories of pipes: **pure** and **impure**.
|
||||
Pipes are pure by default. Every pipe we've seen so far has been pure.
|
||||
We make a pipe impure by setting its pure flag to false. We could make the `FlyingHeroesPipe`
|
||||
impure like this:
|
||||
|
||||
有两类管道:**纯**的与**非纯**的。
|
||||
默认情况下,管道都是纯的。我们以前见到的每个管道都是纯的。
|
||||
通过把它的`pure`标志设置为`false`,我们可以制作一个非纯管道。我们可以像这样让`FlyingHeroesPipe`变成非纯的:
|
||||
|
||||
+makeExample('pipes/ts/app/flying-heroes.pipe.ts', 'pipe-decorator')(format='.')
|
||||
|
||||
:marked
|
||||
Before we do that, let's understand the difference between *pure* and *impure*, starting with a *pure* pipe.
|
||||
|
||||
在继续往下走之前,我们先理解一下*纯*和*非纯*之间的区别,从*纯*管道开始。
|
||||
|
||||
### Pure pipes
|
||||
### 纯管道
|
||||
|
||||
block pure-change
|
||||
:marked
|
||||
|
@ -282,38 +446,65 @@ block pure-change
|
|||
A ***pure change*** is *either* a change to a primitive input value (`String`, `Number`, `Boolean`, `Symbol`)
|
||||
*or* a changed object reference (`Date`, `Array`, `Function`, `Object`).
|
||||
|
||||
Angular只有在它检测到输入值发生了*纯变更*时才会执行*纯管道*。
|
||||
***纯变更***是指对原始类型值(`String`、`Number`、`Boolean`、`Symbol`)的更改,
|
||||
或者对对象引用(`Date`、`Array`、`Function`、`Object`)的更改。
|
||||
|
||||
:marked
|
||||
Angular ignores changes *within* (composite) objects.
|
||||
It won't call a pure pipe if we change an input month, add to an input #{_array}, or update an input object property.
|
||||
|
||||
Angular会忽略(复合)对象*内部*的更改。
|
||||
如果我们更改了输入日期(`Date`)中的月份、往一个输入数组(`Array`)中添加新值或者更新了一个输入对象(`Object`)的属性,Angular都不会调用纯管道。
|
||||
|
||||
This may seem restrictive but is is also fast.
|
||||
An object reference check is fast — much faster than a deep check for
|
||||
differences — so Angular can quickly determine if it can skip both the
|
||||
pipe execution and a view update.
|
||||
|
||||
这可能看起来是一种限制,但它保证了速度。
|
||||
对象引用的检查是非常快的(比递归的深检查要快得多),所以Angular可以快速的决定是否应该在执行管道和更新视图时跳过它。
|
||||
|
||||
For this reason, we prefer a pure pipe if we can live with the change detection strategy.
|
||||
When we can't, we *may* turn to the impure pipe.
|
||||
|
||||
因此,如果我们要和变更检测策略打交道,就会更喜欢用纯管道。
|
||||
如果不能,我们就*可以*转回到非纯管道。
|
||||
|
||||
.l-sub-section
|
||||
:marked
|
||||
Or we might not use a pipe at all.
|
||||
It may be better to pursue the pipe's purpose with a property of the component,
|
||||
a point we take up later.
|
||||
|
||||
|
||||
或者我们也可以完全不用管道。
|
||||
有时候,使用组件的属性能比用管道更好的达到目的,这一点我们等后面会再提起。
|
||||
|
||||
:marked
|
||||
### Impure pipes
|
||||
### 非纯管道
|
||||
|
||||
Angular executes an *impure pipe* during *every* component change detection cycle.
|
||||
An impure pipe will be called a lot, as often as every keystroke or mouse-move.
|
||||
|
||||
Angular会在每个组件的变更检测周期中执行*非纯管道*。
|
||||
非纯管道可能会被调用很多次,和每个按键或每次鼠标移动一样频繁。
|
||||
|
||||
With that concern in mind, we must implement an impure pipe with great care.
|
||||
An expensive, long-running pipe could destroy the user experience.
|
||||
|
||||
要在脑子里绷着这根弦,我们必须小心翼翼的实现非纯管道。
|
||||
一个昂贵、迟钝的管道将摧毁用户体验。
|
||||
|
||||
<a id="impure-flying-heroes"></a>
|
||||
### An impure *FlyingHeroesPipe*
|
||||
### 非纯版本的*FlyingHeroesPipe*
|
||||
|
||||
A flip of the switch turns our `FlyingHeroesPipe` into a `FlyingHeroesImpurePipe`.
|
||||
Here's the complete implementation:
|
||||
|
||||
我们把`FlyingHeroesPipe`换成了`FlyingHeroesImpurePipe`。
|
||||
下面是完整的实现:
|
||||
+makeTabs(
|
||||
'pipes/ts/app/flying-heroes.pipe.ts, pipes/ts/app/flying-heroes.pipe.ts',
|
||||
'impure, pure',
|
||||
|
@ -323,10 +514,19 @@ block pure-change
|
|||
We inherit from `FlyingHeroesPipe` to prove the point that nothing changed internally.
|
||||
The only difference is the `pure` flag in the pipe metadata.
|
||||
|
||||
我们把它从`FlyingHeroesPipe`中继承下来,以证明无需改动内部代码。
|
||||
唯一的区别是管道元数据中的`pure`标志。
|
||||
|
||||
This is a good candidate for an impure pipe because the `transform` function is trivial and fast.
|
||||
|
||||
这是一个很好地非纯管道候选者,因为它的`transform`函数又小又快。
|
||||
|
||||
+makeExample('pipes/ts/app/flying-heroes.pipe.ts','filter')(format='.')
|
||||
|
||||
We can derive a `FlyingHeroesImpureComponent` that we derive from the `FlyingHeroesComponent`.
|
||||
|
||||
我们可以从`FlyingHeroesComponent`派生出一个`FlyingHeroesImpureComponent`。
|
||||
|
||||
+makeExample('pipes/ts/app/flying-heroes.component.ts','impure-component','app/flying-heroes.component.ts (FlyingHeroesImpureComponent)')(format='.')
|
||||
p.
|
||||
The only substantive change is the pipe.
|
||||
|
@ -334,18 +534,26 @@ p.
|
|||
display updates as we enter new heroes even when we mutate the
|
||||
#[code heroes] #{_array}.
|
||||
|
||||
p.
|
||||
唯一的重大改动就是管道。
|
||||
我们可以在#[+liveExampleLink()]中确认,当我们输入新的英雄甚至修改#[code heroes]数组时,这个#[i 会飞的英雄]的显示也跟着更新了。
|
||||
|
||||
- var _dollar = _docsFor === 'ts' ? '$' : '';
|
||||
h3#async-pipe The impure #[i AsyncPipe]
|
||||
h3#async-pipe 非纯管道#[i AsyncPipe]
|
||||
:marked
|
||||
The Angular `AsyncPipe` is an interesting example of an impure pipe.
|
||||
The `AsyncPipe` accepts a `#{_Promise}` or `#{_Observable}` as input
|
||||
and subscribes to the input automatically, eventually returning the emitted value(s).
|
||||
|
||||
Angular的`AsyncPipe`是一个有趣的非纯管道的例子。
|
||||
`AsyncPipe`接受一个`Promise`或`Observable`作为输入,并且自动订阅这个输入,最终返回它们给出的值。
|
||||
|
||||
It is also stateful.
|
||||
The pipe maintains a subscription to the input `#{_Observable}` and
|
||||
keeps delivering values from that `#{_Observable}` as they arrive.
|
||||
|
||||
In this next example, we bind an `#{_Observable}` of message strings
|
||||
In this next example, we bind an `#{_Observable}` of message strings
|
||||
(`message#{_dollar}`) to a view with the `async` pipe.
|
||||
|
||||
+makeExample('pipes/ts/app/hero-async-message.component.ts', null, 'app/hero-async-message.component.ts')
|
||||
|
@ -419,7 +627,7 @@ a(id="pure-pipe-pure-fn")
|
|||
So is our `ExponentialStrengthPipe`.
|
||||
So is our `FlyingHeroesPipe`.
|
||||
A few steps back we reviewed the `FlyingHeroesImpurePipe` — *an impure pipe with a pure function*.
|
||||
|
||||
|
||||
But a *pure pipe* must always be implemented with a *pure function*. Failure to heed this warning will bring about many a console errors regarding expressions that have changed after they were checked.
|
||||
|
||||
.l-main-section
|
||||
|
|
|
@ -11,6 +11,13 @@ td, th {
|
|||
}
|
||||
}
|
||||
|
||||
.translated-cn {
|
||||
em {
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.about-cn-translation {
|
||||
font-size: 16px;
|
||||
h2 {
|
||||
|
|
Loading…
Reference in New Issue