Angular 自定义结构指令

1. <ng-template>元素

import { Component, TemplateRef, ViewContainerRef, ViewChild,
  AfterViewInit } from '@angular/core';
@Component({
  selector: 'app-code404',
  template: `
  <!-- 这里使用一个模板变量,在组件中使用@ViewChild装饰器获取模板元素-->
    <ng-template #tpl>
      Big Keriy !
    </ng-template>
  `,
})
export class Code404Component implements AfterViewInit{

  // @ViewChild 装饰器获取模板元素
  @ViewChild('tpl')
  tplRef: TemplateRef<any>;
  constructor(private vcRef: ViewContainerRef) {}
  ngAfterViewInit() {
    
    // 使用ViewContainerRef对象的createEmbeddedView方法创建内嵌视图。
    this.vcRef.createEmbeddedView(this.tplRef);
  } }

这样其实我们在视图中就得到了一个什么...啊,就是一个'Big Keriy !'的字符串。

2. ngTemplateOutlet指令

a. ngTemplateOutlet
routerOutlet是一个意思,将视图(<ng-template>标签中的内容)放到对应的ngTemplateoutlet下面。

import { Component } from '@angular/core';
  @Component({
    selector: 'app-code404',
    template: `
      <ng-template #stpl>
        Hello, Semlinker!
      </ng-template>
      <ng-template #atpl>
        Big Keriy !
      </ng-template>
      <div [ngTemplateOutlet]="atpl"></div>
      <div [ngTemplateOutlet]="stpl"></div>
`, })
  export class Code404Component { }

最终的视图应该是:

Big Keriy !
Hello, Semlinker!

b. ngOutletContex
看名字就知道意思。
ngTemplateOutlet指令基于TemplateRef对象,在使用ngTemplateOutlet指令时,可以通过ngTemplateOutletContext属性来设置来设置EmbeddedViewRef上下文对象。可以使用let语法来声明绑定上下文对象属性名。

import { Component, TemplateRef, ViewContainerRef, ViewChild,
  AfterViewInit } from '@angular/core';
@Component({
  selector: 'app-code404',
  template: `
    <!-- 这里的messagey映射到下面context中message 再使用插值表达式的方式显示message的值 -->
    <ng-template #stpl let-message="message">
      <p>{{message}}</p>
    </ng-template>
    <!-- 这里的messagey映射到下面context中message , let-msg是一种与语法糖的方式变量名是msg-->
    <ng-template #atpl let-msg="message">
      <p>{{msg}}</p>
    </ng-template>
    <!-- 若不指定变量值那么将显示 $implicit 的值-->
    <ng-template #otpl let-msg>
      <p>{{msg}}</p>
    </ng-template>
    <div [ngTemplateOutlet]="atpl"
          // 这里ngOutletContext绑定的是context对象
         [ngOutletContext]="context">
    </div>
    <div [ngTemplateOutlet]="stpl"
         [ngOutletContext]="context">
    </div>
    <div [ngTemplateOutlet]="otpl"
         [ngOutletContext]="context">
    </div>
  `,
})
export class Code404Component implements AfterViewInit{
  @ViewChild('tpl')
  tplRef: TemplateRef<any>;
  constructor(private vcRef: ViewContainerRef) {}
  ngAfterViewInit() {
    this.vcRef.createEmbeddedView(this.tplRef);
  }
  context = { message: 'Hello ngOutletContext!',
    $implicit: 'great, Semlinker!' };
    // 这里的$implicit是固定写法
}

先看输出的视图:

Hello ngOutletContext!
Hello ngOutletContext!
Hello, Semlinker!

3. ngComponentOutlet指令

听着名字就很爽,这不是插入视图的,是插入组件的!

该指令使用声明的方式,动态加载组件。

先写组件,里面有两个。。组件:

  @Component({
    selector: 'alert-success',
    template: `
      <p>Alert success</p>
    `,
  })
  export class AlertSuccessComponent { }
  @Component({
    selector: 'alert-danger',
    template: `
      <p>Alert danger</p>
    `,
  })
  export class AlertDangerComponent { }
  @Component({
    selector: 'my-app',
    template: `
      <h1>Angular version 4</h1>
      <ng-container *ngComponentOutlet="alert"></ng-container>
      <button (click)="changeComponent()">Change component</button>
  `, })
  export class AppComponent {
     alert = AlertSuccessComponent;
    changeComponent() {
      this.alert = AlertDangerComponent;
  } 
}

当然,还需要在模块中声明入口:

// app.module.ts
@NgModule({
    // ...
    declarations: [
      AppComponent,
      SignUpComponent,
      AlertSuccessComponent,
      AlertDangerComponent
    ],
    entryComponents: [       // 这里面写指令中呀用到的组件
      AlertSuccessComponent,
      AlertDangerComponent
],
// ...
})

这样就可以使用ngComponentOutlet指令来插入组件玩耍了:

<!-- 简单语法 -->
<ng-container *ngComponentOutlet="componentTypeExpression"></ng-container>

<!-- 完整语法 -->
<ng-container *ngComponentOutlet="componentTypeExpression;
     injector: injectorExpression;
     content: contentNodesExpression;">
</ng-container>

这是一个完整语法简单的例子:

// ...
@Component({
  selector: 'ng-component-outlet-complete-example',
  template: `
    <ng-container *ngComponentOutlet="CompleteComponent; 
                                      injector: myInjector; 
                                      content: myContent"></ng-container>`
})
class NgTemplateOutletCompleteExample {
  // This field is necessary to expose CompleteComponent to the template.
  CompleteComponent = CompleteComponent;
  myInjector: Injector;
 
  myContent = [[document.createTextNode('Ahoj')], [document.createTextNode('Svet')]];
 
  constructor(injector: Injector) {
    this.myInjector = ReflectiveInjector.resolveAndCreate([Greeter], injector);
  }
}

4. 创建结构指令

也想不出来一个什么好例子,抄一个例子过来:

// uless.directive.ts

import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
  @Directive({
      selector: '[exeUnless]'
  })
  export class UnlessDirective {
      @Input('exeUnless')
      set condition(newCondition: boolean) {  // set condition
          if (!newCondition) {
              this.viewContainer.createEmbeddedView(this.templateRef);
          } else {
              this.viewContainer.clear();
          } 
      }
      constructor(private templateRef: TemplateRef<any>,
          private viewContainer: ViewContainerRef) {
      } 
  }


  import { Component } from '@angular/core';
  @Component({
    selector: 'app-root',
    template: `
     <h2 *exeUnless="condition">Hello, Semlinker!</h2>
    `,
  })
  export class AppComponent {
    condition: boolean = false;
  }
  
  
  // app.component.ts
  
  import { Component } from '@angular/core';
  @Component({
    selector: 'app-root',
    template: `
     <h2 *exeUnless="condition">Hello, Semlinker!</h2>
    `,
  })
  export class AppComponent {
    condition: boolean = false;
  }

本文部分摘自SemlinkerAngular 4 指令快速入门,感谢作者的分享。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,881评论 4 368
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,052评论 1 301
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,598评论 0 250
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,407评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,823评论 3 294
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,872评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,037评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,778评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,505评论 1 247
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,745评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,233评论 1 264
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,568评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,231评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,141评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,939评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,954评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,784评论 2 275

推荐阅读更多精彩内容