Angular的19个装饰器基本用法

1,493 阅读2分钟
原文链接: github.com

image

@Attribute

获取宿主元素的对应的属性值。

@Directive({
  selector: '[test]'
})
export class TestDirective {
  constructor(@Attribute('type') type ) {
    console.log(type); // text
  }
}
  
@Component({
  selector: 'my-app',
  template: `
    <input type="text" test>
  `,
})
export class App {}

@component

声明组件。

@Component({
  selector: 'greet', 
  template: 'Hello {{name}}!'
})
class Greet {
  name: string = 'World';
}

@ContentChild

@ContentChildren类似,只返回第一个符合的view DOM

@Component({
  selector: 'tabs',
  template: `
    <ng-content></ng-content>
  `,
})
export class TabsComponent {
 @ContentChild("divElement") div: any;
 
 ngAfterContentInit() {
   console.log(this.div);
 }
}

@Component({
  selector: 'my-app',
  template: `
    <tabs>
     <div #divElement>Tada!</div>
    </tabs>
  `,
})
export class App {}

@ContentChildren

@ContentChild类似,获取ng-content中符合的view DOM,只有ngAfterContentInit后才会有view DOMQueryList才会初始化

@Component({
  selector: 'tab',
  template: `
    <p>{{title}}</p>
  `,
})
export class TabComponent {
  @Input() title;
}

@Component({
  selector: 'tabs',
  template: `
    <ng-content></ng-content>
  `,
})
export class TabsComponent {
 @ContentChildren(TabComponent) tabs: QueryList<TabComponent>
 
 ngAfterContentInit() {
   this.tabs.forEach(tabInstance => console.log(tabInstance))
 }
}

@Component({
  selector: 'my-app',
  template: `
    <tabs>
     <tab title="One"></tab>
     <tab title="Two"></tab>
    </tabs>
  `,
})
export class App {}

@directive

声明指令。

@Directive({
  selector: '[my-button]',
  host: {
    '[class.valid]': 'valid', // 动态属性绑定
    'role': 'button', // 静态属性绑定
    '(click)': 'onClick($event.target)' // 事件监听
  }
})
class NgModelStatus {
  constructor(public control:NgModel) {}
  get valid { return this.control.valid; }
  get invalid { return this.control.invalid; }
}

@host

从当前先上获取符合的父view DOM,知道最顶层的宿主元素。

@Component({
  selector: 'cmp',
  template: `
    cmp
  `,
})
export class DIComponent {}

@Directive({
  selector: "[host-di]"
})
export class HostDI {
 constructor(@Host() cmp: DIComponent) {
   console.log(cmp);
 }
}

@Component({
  selector: 'my-app',
  template: `
    <cmp host-di></cmp>
  `,
})
export class App {}

@HostBinding

设置宿主元素的属性绑定。

@Directive({
  selector: '[host-binding]'
})
export class HostBindingDirective {
  @HostBinding("class.tooltip1") tooltip = true; // 设置 "tooltip1" 样式类
  
  @HostBinding("class.tooltip2") // 设置 "tooltip2" 样式类
  get tooltipAsGetter() {
    // your logic
    return true;
  };
   
  @HostBinding() type = "text"; // 直接设置 type="text"
}

@Component({
  selector: 'my-app',
  template: `
    <input type="text" host-binding> // 在这个宿主元素上增加 "tooltip" 样式类
  `,
})
export class App {}

@HostListener

宿主元素的事件监听。

@Directive({
  selector: '[count]'
})
export class HostListenerDirective {
  numClicks = 0;
  numClicksWindow = 0;
  @HostListener("click", ["$event"]) // 当前宿主元素,即input
  onClick(event) {
    console.log(this.numClicks++);
  }
  
  @HostListener("window:click", ["$event"])  //还可以支持 window,document,body 上的事件
  onClick(event) {
    console.log("Num clicks on the window:", this.numClicksWindow++);
  }
}

@Component({
  selector: 'my-app',
  template: `
    <input type="button" count value="+">
  `,
})
export class App {}

@Inject

指明依赖。

@Component({
  selector: 'cmp',
  template: `
    cmp
  `
})
export class DIComponent {
  constructor(@Inject(Dependency) public dependency) {}
}

@Injectable

声明类可以被DI使用。

@Injectable()
export class WidgetService {
  constructor(
    public authService: AuthService) { }
}

@input

定义组件的属性。

@Component({
  selector: 'my-button',
  template: `
    <button (click)="click($event)">{{name}}</button>
  `
})
export class DI2Component {

  @Input() name ;

  @Output() myClick: EventEmitter<any> = new EventEmitter();

  click() {
    this.myClick.emit('click');
  }
}

@NgModule

定义module。

@NgModule({
  imports: [ CommonModule ],
  declarations: [
    DIComponent,
    HostBindingDirective,
    HostDI
  ],
  providers: [{ provide: Dependency, useClass: ParentDependency}],
  exports: [
    DIComponent,
    HostBindingDirective,
    HostDI
  ]
})
export class DemoModule {}

@optional

依赖可选

class OptionalDependency {}

@Component({
  selector: 'cmp',
  template: `
    cmp
  `,
})
export class DIComponent {
  constructor(@Optional() public dependency: OptionalDependency) {}
}

@output

定义组件的事件。

@Component({
  selector: 'my-button',
  template: `
    <button (click)="click($event)">{{name}}</button>
  `
})
export class DI2Component {

  @Input() name ;

  @Output() myClick: EventEmitter<any> = new EventEmitter();

  click() {
    this.myClick.emit('click');
  }
}

@pipe

定义管道。

@Pipe({
  name: 'isNull'
})
export class IsNullPipe implements PipeTransform {
  
  transform (value: any): boolean {
    
    return isNull(value);
  }
}

@self

只使用自身的providers的定义,不通过inject tree查找依赖。

class Dependency {}

class ChildDependency {
 constructor() {
   console.log("ChildDependency");
 }
}

class ParentDependency {
 constructor() {
   console.log("ParentDependency");
 }
}

@Component({
  selector: 'cmp',
  template: `
    cmp
  `,
  providers: [{ provide: Dependency, useClass: ChildDependency }]
})
export class DIComponent {
  constructor(@Self() public dependency: Dependency) {} // 注入的为 ChildDependency
}

@Component({
  selector: 'my-app',
  template: `
    <cmp></cmp>
  `,
})
export class App {}

@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App,  DIComponent],
  providers: [{ provide: Dependency, useClass: ParentDependency }],
  bootstrap: [ App ]
})
export class AppModule {}

@SkipSelf

自身组件中定义的providers无效,从parent injector中查找依赖。

class Dependency {}

class ChildDependency {
 constructor() {
   console.log("ChildDependency");
 }
}

class ParentDependency {
 constructor() {
   console.log("ParentDependency");
 }
}

@Component({
  selector: 'cmp',
  template: `
    cmp
  `,
  providers: [{ provide: Dependency, useClass: ChildDependency }]
})
export class DIComponent {
  constructor(@SkipSelf() public dependency: Dependency) {}
}

@Component({
  selector: 'my-app',
  template: `
    <cmp></cmp>
  `,
})
export class App {}

@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App,  DIComponent],
  providers: [{ provide: Dependency, useClass: ParentDependency }],
  bootstrap: [ App ]
})
export class AppModule {}

@ViewChild

@ViewChildren类似,不同点是只获取第一个符合的view DOM,不能获取ng-content中的内容。

@Component({
  selector: 'alert',
  template: `
    {{type}}
  `,
})
export class AlertComponent {
  @Input() type: string = "success";
}

@Component({
  selector: 'my-app',
  template: `
    <alert></alert>
    <div #divElement>Tada!</div>
  `,
})
export class App {
  // This will return the native element
  @ViewChild("divElement") div: any;
  // This will return the component instance
  @ViewChild(AlertComponent) alert: AlertComponent;
  
  ngAfterViewInit() {
    console.log(this.div);
    console.log(this.alert);
  }
}

@ViewChildren

@ViewChild类似,获取view DOM集合,ngAfterViewInitQueryList才会初始化。

@Component({
  selector: 'alert',
  template: `
    {{type}}
  `,
})
export class AlertComponent {
  @Input() type: string = "success";
}

@Component({
  selector: 'my-app',
  template: `
    <alert></alert>
    <alert type="danger"></alert>
    <alert type="info"></alert>
  `,
})
export class App {
  // 获取组件实例
  @ViewChildren(AlertComponent) alerts: QueryList<AlertComponent>
  
  // 获取DOM element
  @ViewChildren(AlertComponent, { read: ElementRef }) alerts2: QueryList<AlertComponent>

  // 需要动态创建组件或者模板时,需要获取 ViewContainerRef
  @ViewChildren(AlertComponent, { read: ViewContainerRef }) alerts3: QueryList<AlertComponent>
  
  ngAfterViewInit() {
    this.alerts.forEach(alertInstance => console.log(alertInstance));
    this.alerts2.forEach(alertInstance => console.log(alertInstance));
  }
}