Angular2管道的笔记
结论。
现在不可能
我完全理解了 (有点小自豪感)
管子,比我想象的厉害多了。多亏了@shuhei的评论,我能够大步向前了。
准备准备
创建Pipe
在中文中,我们可以这样翻译上述内容:
Pipe类是继承自Pipe类的一个类。继承自Pipe类的类必须具备supports和transform这两个方法。另外,我们还需要创建一个用于实例化Pipe对象的PipeFactory。PipeFactory类必须具备create方法。这两者并不一定需要是不同的类,Pipe类本身也可以充当PipeFactory的角色。
接收一个字符串,定义如下的Pipe和其Factory,使其重复两次。
import 'package:angular2/change_detection.dart';
class DoublePipeFactory extends Pipe {
bool supports(obj) {
return obj is String;
}
dynamic transform(dynamic value) {
return "${value}${value}";
}
Pipe create(ChangeDetectorRef cdRef) {
return this;
}
}
从Pipe类中进行覆盖的是以下两个方法。
是否支持(obj)
给定一个动态类型(JS中为any?)的对象,并判断管道是否有效。给定的对象是在使用管道时的左侧。由于本次仅限制为字符串类型,所以当为String类型时返回true。
动态转换(动态值)
进行Pipe的转换操作。返回类型不需要与参数匹配,例如可以创建一个接收列表并返回仅包含第一个元素的Pipe。
我们已经实现了以下方法来作为PipeFactory的行为。
创建一个管道(ChangeDetectorRef cdRef)。
返回Pipe的实例。由于此次Pipe本身兼具工厂功能,因此返回this。参数cdRef用于控制更新时机,但在同步处理范围内不需要使用。具体的使用方法可以参考内置的AsyncPipe实现。
将信息注册到PipeRegistry
创建的Pipe可以通过将其注册到PipeRegistry中,使其能够在Angular中作为Pipe使用。由于还没有简洁的API来进行注册,所以目前的实现相对较为笨拙。是否有改进的空间呢?
将Pipe添加到defaultPipeRegistry。
从已注册的defaultPipeRegistry中提取config,这是一个内部映射,其中包含keyValDiff、iterableDiff、async等内置的Pipe。然后创建一个新的配置,其中嵌入自定义的Pipe。需要注意的是,传递给映射的不是Pipe也不是PipeFactory,而是PipeFactory的列表。这是为了按优先顺序提取具有相同名称的PipeFactory列表中的第一个Pipe实例,并调用supports方法使用它。
import 'package:angular2/change_detection.dart';
import 'double/double.dart';
import 'filter/filter.dart';
dynamic get pipes {
var config = defaultPipeRegistry.config;
config["double"] = [new DoublePipeFactory()];
return config;
}
注册应用程序
在Angular2启动时,将创建的配置注册到绑定中。
import "package:angular2/src/reflection/reflection.dart";
import "package:angular2/src/reflection/reflection_capabilities.dart";
import 'package:helloworld/component/app_component.dart';
import 'package:angular2/di.dart';
import 'package:helloworld/pipe/pipes.dart';
main() {
reflector.reflectionCapabilities = new ReflectionCapabilities(); //dart版では暫定的に必要らしいコードなので無視
var injectables = [bind(PipeRegistry).toValue(new PipeRegistry(pipes))];
bootstrap(AppComponent, injectables);
}
用
只要完成注册,之后就只需要使用了。
在{{}}之中使用
我们将创建一个名为double-value的组件,它是一种非常简单的形式。它会将文本属性的字符串重复两次显示。
import "package:angular2/angular2.dart";
import 'package:helloworld/component/double/double_component.dart';
@Component(selector: 'my-app')
@View(
templateUrl: 'component/app.html',
directives: const [DoubleComponent])
class AppComponent {
var text = "ABC";
AppComponent() {}
}
<double-value [text]="text"></double-value>
import "package:angular2/angular2.dart";
@Component(selector: "double-value", properties: const {"text": "text"})
@View(templateUrl: "component/double.html")
class DoubleComponent {
String text;
}
<h2>Double Pipe</h2>
<span>{{ text | double }}</span>

我们制作了一个专门用于便宜的组件,但当然也可以在根HTML中使用。
在属性的值中使用
这是一个在使用for循环时的情境。在将值传递给Directive之前,会先应用Pipe。如果将前一个app.html修改如下,当将值传递给Directive时,Pipe将会作用两次,分别在内部和外部。
<double-value [text]="text | double"></double-value>

在Directive定義中使用
由于这个用法,非常混乱。这是一种在脚本中而不是HTML中应用Pipe的语法。在@Component的properties中使用。
当传递给Directive的值被绑定到内部属性时,Pipe会被应用。因此,通过修改double_component.dart如下,可以再次通过Pipe传递一次,总共发生3次重复。
import "package:angular2/angular2.dart";
@Component(selector: "double-value", properties: const {"text": "text | double"})
@View(templateUrl: "component/double.html")
class DoubleComponent {
String text;
DoubleComponent() : super() {}
}

通过将属性绑定到setter函数,可以看到管道在绑定后仍在起作用,就像下面的例子一样。
import "package:angular2/angular2.dart";
@Component(
selector: "double-value", properties: const {"textChange": "text | double"})
@View(templateUrl: "component/double.html")
class DoubleComponent {
String text;
set textChange(String newText) {
this.text = newText + "_";
}
DoubleComponent() : super() {}
}

当收到不支持的对象时的行为
如果将数字100传递给双管道(double Pipe),那么将从PipeRegistry的double中注册的PipeFactory中查找supports(100) == true的Pipe,如果找不到,则会出现错误提示。
Cannot find 'double' pipe supporting object '100' in [text| double in AppComponent]
总结
现在说什么都太勉强了,对不起!
虽然还有点早,但已经到了可以使用的水平。
由于是Dart版,细节可能与JS不同,请尽量克服这些困难。在Angular2的世界中,Dart和JS的区别不过是微不足道的事情。
希望未来能改善的方面是
-
- PipeRegistry周りもうちょっとAPI整備して綺麗に書けるようにしてくれ
- なぜPipeFactoryはクラスがないのか…(createメソッドがないとダメだっていうエラーは出すくせに)
只是大约这样。
以上的内容。