Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

angular2 管道(pipes) #1

Open
JTangming opened this issue Mar 21, 2016 · 0 comments
Open

angular2 管道(pipes) #1

JTangming opened this issue Mar 21, 2016 · 0 comments

Comments

@JTangming
Copy link
Owner

1.管道

我们的很多应用场景是基于这样一个简单的任务,获取数据,转换过滤后再展示给用户,angular2中我们引入了管道(Pipes)的概念,即管道是用来将数据模型中的数据经过过滤转换,然后通过模板内并展示给用户,这样做是为了更好的用户体验,例如从视图模型中直接获得的数据,不一定完全是我们想要的格式或者适合于人们查看的,举个例子,我们需要获取一个班级所有学生的平均分:

<div>this class‘s average is: {{getAvgScore()}}</div>

虽然通过视图模型中的getAvgScore方法获取到了我们需要的平均分来展示了,但是可能我们获取到的数据是一个除不断的多位小数位的数据,那么这样的结果看上去是不那么顺眼的。除了在视图模型的方法来控制小数位外,我们也可以利用管道来格式化这样的数据,也就是在模板里改变数据的显示格式。这就是angular2中管道的作用。

1.1 管道的用法

在angular2中,管道是在模板中对输入数据进行变换,并输出变换后的结果。在模板的内嵌表达式中,使用管道操作符“|”和其右边的管道方法来实现一个管道操作,使用“:”来向管道传入参数,所有的管道都是沿用这样这的一种机制。我们举个简单的例子来说明一下管道的使用:

import {Component} from 'angular2/core'
@Component({
    selector: 'hero-birthday',
    template: `<p>The hero's birthday is {{ birthday | date:"MM/dd/yy" }}</p>`
})
export class HeroBirthday {
    birthday = new Date(1988,3,15); // April 15, 1988
}

我们通过视图组件获取到我们要输出的生日日期birthday,通过插值和模板联系起来,在模板的内嵌表达式中,我们输出生日组件的值是通过管道操作符“|”和其右边的内置管道Data Pipe方法来实现的。至于管道的参数,我们在内置管道Data Pipe方法后边加冒号(:)来添加参数值,并且如果有多个参数的话,我们用多个冒号来区分开参数就好了。

最后要说一下的是,angular2管道可以链式运用。我们可以将多个管道通过“|”链式的书写到一个实用的组合体上,如我们将birthday链到DatePipe和UpperCasePipe上以便我们将生日日期显示为大写,下面的日期将会是APR 15, 1988:

<p>The chained hero's birthday is {{ birthday | date | uppercase}}</p>

1.2 管道的内置方法

为了方便使用,Angular2针对之前的经验,设置了一套常用的内置管道,如DatePipe,JsonPipe,UpperCasePipe, LowerCasePipe,CurrencyPipe,PercentPipe及SlicePipe.其目的是在任何模板中都可以便捷使用。我们将详细介绍他们的具体用法。
DatePipe是对日期\时间数据进行格式变换,在模板中直接使用date来引用DatePipe,参数用来指定所需的格式,需要说明的是,不需要再在视图组件中声明,

 <p>{{day | date: 'yyMMdd'}}</p>

JsonPipe是将Json数据对象转换成字符串格式输出,在模板中使用json来引用JsonPipe,其实现是基于JSON.stringify(),这个管道主要用来调试。

<p>{{key1: "value1", key2: "value2"}} | json</p>

UpperCasePipe&LowerCasePipe用于将输入的字符串转换成大小写,在模板中直接使用uppercase&lowercase即可。

<p>{{“this is a demo” | uppercase}} | json</p>

CurrencyPipe是将获取到的金钱数转换成特定格式的数字,在模板中直接使用currency来引用CurrencyPipe。

<p>{{price | currency: 'USD': true}}</p>

PercentPipe是将数值转换成百分比,在模板中使用percent来引用PercentPipe即可。

<p>{{1.23456 | percent: '1.2-3'}} | json</p>

例子中的“:'1.2-3'”表示调用这个这个管道时传入的参数为“'1.2-3'”,对于PercentPipe,这三个数字分别依次表示最少整数位、最少小数位和最多小数位。

SlicePipe是用来提取输入字符串中的指定切片,在模板中使用slice来引用SlicePipe。第一个参数指定切片的起始索引,第二个参数指定切片的终止索引的下一个。

<p>{{ '01234567890' | slice:1:4 }}</p>

2.自定义管道

通过上一节的内置管道可以看出,angular2内置的管道并不是特别的丰富,更进一步的是angular2允许自定义管道。自定义一个管道需要以下两个步骤:

2.1、声明元数据

和实现一个组件类似,一个自定义的管道也是具有特定元数据的类,如

import {Component,Pipe} from "angular2/core";
@Pipe({name: "anyPipeName"})
class anyPipeNamePipe {...}

Pipe注解为被装饰的类附加了管道元数据,其最重要的属性是name,也就是我们在模板中调用这个管道时使用的名称。上面定义的管道,我们可以在模板中这样使用:

<p>{{ data | anyPipeName }}</p>

2.2 实现transform方法

定义一个自定义的管道必须实现一个预定的方法transform(input,args),其中这个方法的input参数代表输入数据,args参数代表输入参数,返回值将被作为管道的输出。

import {Component,Pipe} from "angular2/core";
@Pipe({name: "anyPipeName"})
class anyPipeNamePipe {
    transform(input,args){
        return ...;
    }
}

通过以上定义一个自定义的管道,需要说明的是这样的一个pipe需要以下这样几个关键的点:

  • 管道是一个带有pipe元数据的类;
  • 这个类实现一个转换方法,通过一个输入值和一个可选的数组字符参数,最终返回转换后的值;
  • 数组参数中的某一项将每一个参数传递给pipe;
  • 我们通知Angular这是一个引入过Angular核心库的@pipe服务
  • 这个@pipe服务带有一个参数,该参数它的值是一个pipe名,我们将使用在一个模板表达式中,它可以是一个合法的Javascript定义。

最后我们通过例子来说明自定义管道的使用,但是需要特别注意的是:

  • 在组件的模板中使用自定义管道之前,需要预先声明一下,即使用Component注解的pipes属性进行声明:pipes:[EzPipe],以便Angular2注入。
  • 如果我们忽视去列出我们的自定义pipe,Angular2将会报错。我们不需要在先前的例子中列出内置指令是因为所有Angular2内置的pipes是预先注册过的,自定义的pipes必须手动注册。

自定义管道完整的例子如下:

import {Component,Pipe} from "angular2/core";
import {bootstrap} from "angular2/platform/browser";

@Pipe({name:"title"})
class TitlePipe{
    transform(input,args){
        return input.split(" ")
                .map(word => word[0].toUpperCase() + word.slice(1))
                .join(" ");
    }
}

@Component({
    selector:"Demo-app",
    template:`  
        <p>{{text | title}}</p>
    `,
    pipes : [TitlePipe]
})
class DemoApp{
    constructor(){
        this.text = "what a wonderful world!";
    }
}

bootstrap(DemoApp);

3.管道状态

3.1 无状态的管道

无状态的管道是一个纯粹的方法,流入的数据将不会记录任何东西,或者不会导致任何的副作用。大多数的管道是无状态的,例如我们之前例子的Datapipe就是一个无状态的pipe。据我们之前了解到的管道,包括angular2内置的管道,都具有这么一个特点,就是其输出仅仅是依赖于输入,这就是angular2中的无状态管道,对于无状态的管道,当视图组件的输入没有变化时,angular2框架是不会重新计算管道的输出的。

3.2 有状态的管道

有状态的管道在概念上类似于面向对象编程类,它们可以管理数据的变换,例如管道创建一个HTTP请求,存储它的返回和显示结果,就是一个有状态的pipe。需要注意的是,检索或请求数据的管道应该要谨慎使用,因为使用网路数据往往会引入错误的条件,在javascript中处理更优于在模板中处理。我们可以为了特定的后端和基本的异常捕获而创建自定义的pipe来减轻任何风险。

angular2对有状态的管道定义的关键在于使用使用Pipe注解的属性“pure”,并设置该属性的值为false即可,其作用是要求angular2框架在每个变化检查周期都执行管道的transform()方法。下面我们给一个例子,实现一个10到0的倒数计时器。

import {Component,Pipe} from "angular2/core";
import {bootstrap} from "angular2/platform/browser";

@Pipe({
    name : "countdown",
    pure : false
})
class CountdownPipe {
    transform(input){
        this.initOnce(input);
        return this.counter;
    }
    initOnce(input){
        this.counter = input;
        this.timer = setInterval(() => {
            this.counter--;
            if(this.counter === 0) 
                clearInterval(this.timer);
        }, 1000);
    }
}
@Component({
    selector:"demo-app",
    template:`<h1>this is a stateful pipe : {{ 10 | countdown }}</h1>`,
    pipes : [CountdownPipe]
})
class DemoApp{} 
bootstrap(DemoApp);

从这个例子中可以看出,自定义管道countdownPipe的输出不仅依赖输出,还依赖与其内部的变化或者运行状态。

而angular2中,AsyncPipe是有状态管道的一个标志性的例子,AsyncPipe它的输入是一个异步对象:Promise对象、Observable对象或者EventEmitter对象,并且自动的订阅(subscrib)输入对象,最终每当异步对象产生新的值,AsyncPipe会返回这个新的值,它的有状态性是因为pipe维护一个输入的订阅并且它的返回值也依赖于这个订阅器。下面给出的例子,我们将用AsyncPipe绑定一个简单的promise给一个view。

import {Component} from 'angular2/core';
// Initial view: "Message: "
// After 500ms: Message: You are my Hero!"
@Component({
    selector: 'hero-message',
    template: 'Message: {{delayedMessage | async}}',
})
export class HeroAsyncMessageComponent {
    delayedMessage: Promise<string> = new Promise((resolve, reject) => {
    setTimeout(() => resolve('You are my Hero!'), 500);
    });
}

3.3 管道无状态和有状态的区别

管道的有状态和无状态的区别,关键在于是否是需要Angular2框架在输入不变的情况下依然持续地进行变化检测,而angular2的无状态的管道是依赖输入的,即同样的输入,总是产生同样的输出。举个例子,例如我们上面的管道,当我们输入一个默认的数字后,输出值依赖其内部的运行状态变化,而无状态的管道,例如一个加减乘除的管道,在Angular2中,它被视为无状态的,因为它的一次输入不会产生多次输出。

@JTangming JTangming changed the title NG-2 管道(pipes) angular2 管道(pipes) Mar 28, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant