ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
结构性指令是通过添加和移除 DOM 元素改变 DOM 布局。 * 每个宿主元素上只能有一个结构型指令 * 在使用结构型指令操作时,需要明白Angular 会继续检查哪些能影响数据绑定的变更。 组件原本要做的那些事情仍在继续。 >如:对于简单的段落,隐藏和移除之间的差异影响不大,但对于资源占用较多的组件不一样。 当隐藏掉一个元素时,组件的行为还在继续 —— 它仍然附加在它所属的 DOM 元素上,也仍在监听事件。 打造属于自己的结构型指令,很像创建属性型指令: * 导入 Directive 装饰器。 * **必须导入**符号 Input、TemplateRef 和 ViewContainerRef,因为必须有值来确定是什么样的结构。 * 给指令类添加装饰器。 * 使用 templateRef 取得`<ng-template>`的内容,并通过ViewContainerRef来访问这个视图容器。 ## 前言 星号(*)是一个用来简化更复杂语法的“语法糖”,从内部实现来说:以`*ngIf`为例,Angular 把 `*ngIf`属性翻译成一个`<ng-template>` 元素,并用它来包裹宿主元素。 ``` <ng-template [ngIf]="bool"> <div class="name">{{hero.name}}</div> </ng-template> ``` ### `<ng-template>` 指令 `<ng-template>`是一个 Angular 元素,用来渲染 HTML。 它永远不会直接显示出来。 事实上,在渲染视图之前,Angular 会把 `<ng-template> `及其内容替换为一个注释。如果没有使用结构型指令,仅仅把一些别的元素(这些元素不可见的)包装进 `<ng-template>` 中。 ``` <p>Hi!</p> <ng-template> <p>mary</p> </ng-template> <p>Welcome</p> ``` 如上面代码,mary不会显示,但结构型指令会让 `<ng-template>` 正常工作。 ### `<ng-container>` 指令 `<ng-container>` 是Angular的一个分组元素,但它不会污染样式或元素布局,因为 Angular 压根不会把它放进 DOM 中。 使用 `<ng-container>`实现的条件化段落 ``` <p> I turned the corner <ng-container *ngIf="bool"> and saw {{name}}. I waved </ng-container> and continued on my way. </p> ``` ![](https://img.kancloud.cn/3f/43/3f43e03fa511961b6e8974cdb925f7fe_546x350.png) ### TemplateRef 和 ViewContainerRef 结构型指令会从 Angular 生成的 `<ng-template>` 元素中创建一个内嵌的视图,并把这个视图插入到一个视图容器中。可以使用`TemplateRef` 取得`<ng-template>`的内容,并通过`ViewContainerRef`来访问这个视图容器。可以把它们都注入到指令的构造函数中,作为该类的私有属性。 ## 创建结构型指令步骤 创建自定义结构型指令appUnless,功能: ① 把一个 true/false 条件绑定到 `[appUnless]` 属性上; ② 实现与`*ngIf`相反的功能。 >指令和组件一样,必须在Angular模块中进行声明,指令所在的元素就是它的宿主元素。 ### 第一步:创建指令文件 在存放指令的文件夹(src/app/directives)下执行cli命令:`ng generate directive unless(简写ng g d unless)` ``` src\app\directive>ng generate directive unless CREATE src/app/directive/unless.directive.spec.ts (224 bytes) CREATE src/app/directive/unless.directive.ts (141 bytes) UPDATE src/app/app.module.ts (493 bytes) ``` 会自动帮我们创建unless文件(`src/app/directives/unless.directive.ts`)和相应的测试文件(`src/app/directives/unless.directive.spec.ts`)。 unless.directive.ts 文件 ``` import { Directive } from '@angular/core'; @Directive({ selector: '[appUnless]' }) export class UnlessDirective { constructor() { } } ``` ### 第二步:在根模块AppModule中声明指令类 使用命令`ng generate directive unless`,会自动帮我们在根模块AppModule中声明这个指令类。 app.module.ts文件 ``` import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { UnlessDirective} from './directive/unless.directive'; @NgModule({ declarations: [ AppComponent, UnlessDirective ], imports: [ BrowserModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { } ``` ### 第三步:编写unless指令 ``` /* 导入 Directive 装饰器,导入符号 TemplateRef, ViewContainerRef, Input */ import {Directive, TemplateRef, Input, ViewContainerRef} from '@angular/core'; @Directive({ /* 指定指令的属性型选择器 */ selector: '[appUnless]' }) export class UnlessDirective { private hasView = false; @Input() set appUnless(condition: boolean) { if (!condition && !this.hasView) { this.viewContainer.createEmbeddedView(this.templateRef); this.hasView = true; } else if (condition && this.hasView) { this.viewContainer.clear(); this.hasView = false; } } /* 构造函数中使用 templateRef 取得<ng-template>的内容,并通过ViewContainerRef来访问这个视图容器 */ constructor(private templateRef: TemplateRef<any>, private viewContainer: ViewContainerRef) { } } ``` ### 第四步:宿主元素使用 ``` <!-- ts里定义 condition = false; --> <p *appUnless="condition" class="unless a"> (A) This paragraph is displayed because the condition is false. </p> <p *appUnless="!condition" class="unless b"> (B) Although the condition is true, this paragraph is displayed because appUnless is set to false. </p> ``` ![](https://img.kancloud.cn/60/47/6047e81e04b9562046ac485db742e7ac_658x272.png)