angular6.x系列的学习笔记记录,仍在不断完善中,学习地址:

https://www.angular.cn/guide/template-syntax

http://www.ngfans.net/topic/12/post/2

系列目录

(1)组件详解之模板语法

(2)组件详解之组件通讯

(3)内容投影, ViewChild和ContentChild

(4)指令

(5)路由

指令

大家应该都知道,在html中存在一些附加在元素节点上的标记,例如属性,事件等等.它们能够改变元素的行为,甚至操作DOM,改变DOM元素,以及它的各级子节点.

那么,在angular中也有这样的存在,那就是指令.

在 Angular 中有三种类型的指令:

  1. 组件 — 组件的特殊存在,拥有模板

  2. 结构型指令 — 通过添加和移除 DOM 元素改变 DOM 布局的指令,常用的有:*ngIf,*ngFor,ngSwitch

  3. 属性型指令 — 改变元素、组件或其它指令的外观和行为的指令,常用的有:NgClass,NgStyle

组件

在查看源代码,我们会发现这样的画面

所以说组件是继承指令的,只是它比较特殊,有模版

同样,因为组件继承指令,在下面属性型和结构型指令的一系列操作,在组件中都是可以实现的

但是因为指令的目的是为了复用,在组件中这样操作是达不到这个目的,所以强烈不推荐这样去操作.

这里就不多做说明,有兴趣可以自己尝试一下

属性型指令

上面说道属性型指令是用来改变元素、组件或其它指令的外观和行为

那么我们如何打造属于自己的属性型指令呢?

首先,创建指令很像创建组件。

  • 导入 Directive 装饰器(而不再是 Component)。

  • 导入符号 Input、TemplateRef 和 ViewContainerRef,视指令类型与需求来选择

  • 给指令类添加装饰器。

  • 设置 CSS 属性选择器 ,以便在模板中标识出这个指令该应用于哪个元素。

对于指令而言,至少需要一个带有@Directive装饰器的控制器类。该装饰器指定了一个用于标识属性的选择器。 控制器类实现了指令需要的指令行为。

在我们存放指令的文件夹下(例如src/app/directives)下执行下面cli命令

ng generate directive name(简写ng g d name)

就可以快速得到src/app/directives/name.directive.ts和相应的测试文件src/app/directives/name.directive.spec.ts

并且在根模块AppModule中声明这个指令类。

根据命令快速创建一个名为highlight的指令。基本代码如下:

 import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HighlightDirective } from './directive/highlight.directive'; @NgModule({
declarations: [
AppComponent,
HighlightDirective,
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
 import { Directive } from '@angular/core';

 @Directive({
selector: '[appHighlight]'
})
export class HighlightDirective { constructor() { } }

Warnning

和组件一样,这些指令也必须在Angular模块中进行声明

指令所在的元素就是它的宿主元素

下面以一个实例展示如何自定义属性型指令:highlight的功能如下

1能够接收2个参数,其中一个为另外一个的默认值

2监听宿主元素的鼠标进入和离开事件,在进入时宿主背景颜色为上述传入的值

具体代码如下

src/app/directives/highlight.directive.ts

 import { Directive, ElementRef, HostListener, Input } from '@angular/core';

 @Directive({
//指定指令的属性型选择器
selector: '[appHighlight]'
}) export class HighlightDirective {
@Input('appHighlight') highlightColor: string;
@Input() defaultColor: string; //构造函数中使用 ElementRef 来注入宿主 DOM 元素的引用
constructor(private el: ElementRef) { } //监听宿主元素mousenter事件
@HostListener('mouseenter') onMouseEnter() {
this.highlight(this.highlightColor || this.defaultColor);
} //监听宿主元素mousenter事件
@HostListener('mouseleave') onMouseLeave() {
this.highlight(null);
} private highlight(color: string) {
//ElementRef通过其 nativeElement 属性,提供直接访问宿主 DOM 元素的能力。
this.el.nativeElement.style.backgroundColor = color;
}
}

宿主元素用法

<p appHighlight="red" defaultColor="black">宿主元素</p>

最终效果

结构性指令

结构性基本知识和上面的属性型指令差不多,但是它必须导入 Input、TemplateRef 和 ViewContainerRef,因为我们必须得有值来确定的是什么样的结构.

在说道结构性指令的时候,例如*ngIf,*ngFor(ngSwitch其实也有,不过是在内部),都会看到前面有一个*号,它是用来干嘛的呢?

其实这里星号是一个用来简化更复杂语法的“语法糖”,从内部实现来说:以*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> 中,那些元素就是不可见的。

在下面的这个短语"Hip! Hip! Hooray!"中,中间的这个 "Hip!"不会显示就是如此。

 <p>Hip!</p>
<ng-template>
<p>Hip!</p>
</ng-template>
<p>Hooray!</p>

但是结构型指令会让 <ng-template> 正常工作,在下面自定义结构型指令时就会看到这一点.

<ng-container> 指令

Angular 的 <ng-container> 是一个分组元素,但它不会污染样式或元素布局,因为 Angular 压根不会把它放进 DOM 中。

下面是重新实现的条件化段落,这次使用 <ng-container>,都可以显示

 <p>
I turned the corner
<ng-container *ngIf="bool">
and saw {{hero.name}}. I waved
</ng-container>
and continued on my way.
</p>

TemplateRef 和 ViewContainerRef

像上面简单结构型指令例子,会从 Angular 生成的 <ng-template> 元素中创建一个内嵌的视图,并把这个视图插入到一个视图容器中.可以使用TemplateRef取得 <ng-template> 的内容,并通过ViewContainerRef来访问这个视图容器。可以把它们都注入到指令的构造函数中,作为该类的私有属性,详见下面自定义结构型指令

自定义结构型属性

我们来自定义一个名为appUnless的结构型指令,该指令的使用者会把一个 true/false 条件绑定到 [appUnless] 属性上。实现与*ngIf相反的功能

具体代码如下

 import { Directive, TemplateRef, Input, ViewContainerRef } from '@angular/core';

 @Directive({
selector: '[appUnless]'
})
export class UnlessDirective { private hasView: boolean = 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;
}
} constructor(
private templateref: TemplateRef<any>,
private viewContainer: ViewContainerRef
) { } }
<!-- ts里定义 condition: boolean = 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>

效果如下

对于简单的段落,隐藏和移除之间的差异影响不大,但对于资源占用较多的组件是不一样的。 当隐藏掉一个元素时,组件的行为还在继续 —— 它仍然附加在它所属的 DOM 元素上, 它也仍在监听事件。Angular 会继续检查哪些能影响数据绑定的变更。 组件原本要做的那些事情仍在继续。所在在使用结构型指令操作时,我们需要明白这一点

Warnning

每个宿主元素上只能有一个结构型指令,你可能试过把 *ngFor 和 *ngIf 放在同一个宿主元素上,但 Angular 不允许。这是因为你在一个元素上只能放一个结构型指令。

内置指令

angular自带的有许多内置的指令,下面可以看见许多熟悉的身影:

详情参见官网传送门,大家有兴趣就多去看看

(终)

文档信息


感谢您的阅读,如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮。本文欢迎各位转载,但是转载文章之后必须在文章页面中给出作者和原文连接

Angular6 学习笔记——指令的更多相关文章

  1. Angular6 学习笔记——内容投影, ViewChild和ContentChild

    angular6.x系列的学习笔记记录,仍在不断完善中,学习地址: https://www.angular.cn/guide/template-syntax http://www.ngfans.net ...

  2. Angular6 学习笔记——组件详解之组件通讯

    angular6.x系列的学习笔记记录,仍在不断完善中,学习地址: https://www.angular.cn/guide/template-syntax http://www.ngfans.net ...

  3. Angular6 学习笔记——组件详解之模板语法

    angular6.x系列的学习笔记记录,仍在不断完善中,学习地址: https://www.angular.cn/guide/template-syntax http://www.ngfans.net ...

  4. Angular6 学习笔记——路由详解

    angular6.x系列的学习笔记记录,仍在不断完善中,学习地址: https://www.angular.cn/guide/template-syntax http://www.ngfans.net ...

  5. 汇编学习笔记(11)int指令和端口

    格式 int指令也是一种内中断指令,int指令的格式为int n,n是中断类型码.也就是说,使用int指令可以调用任意的中断例程,例如我们可以显示的调用0号中断例程,还记得在汇编学习笔记(10)中我们 ...

  6. java web jsp学习笔记--概述-常用语法,指令,动作元素,隐式对象,域对象

     JSP学习笔记 1.什么是jsp JSP全称是Java Server Pages,它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术.JSP/Servlet规范.JS ...

  7. angular学习笔记(6)- 指令

    angular1学习笔记(6)- 指令 restrict-匹配模式 1.A - 属性 <my-menu title=Products></my-menu> 2.M - 注释 & ...

  8. angular学习笔记(三十)-指令(10)-require和controller

    本篇介绍指令的最后两个属性,require和controller 当一个指令需要和父元素指令进行通信的时候,它们就会用到这两个属性,什么意思还是要看栗子: html: <outer‐direct ...

  9. angular学习笔记(三十)-指令(7)-compile和link(2)

    继续上一篇:angular学习笔记(三十)-指令(7)-compile和link(1) 上一篇讲了compile函数的基本概念,接下来详细讲解compile和link的执行顺序. 看一段三个指令嵌套的 ...

随机推荐

  1. iis 应用程序连接池 在计算机“.”上没有找到WAS服务

    重新打开控制面板----打开或关闭windows功能,全部勾选internet information services 可承载的web核心. internet信息服务.microsoft.net f ...

  2. Swift 项目中可能用到的第三方框架

    这里记录下swift开发中可能用的框架 , 最近浏览了不少,积累在这里,以后用的时候方便查阅.顺便推荐给大家! 这里的框架都是纯swift的 , 感谢开源 ,感谢大神们 . 下拉刷新 BreakOut ...

  3. ROS Learning-008 beginner_Tutorials ROS话题

    ROS Indigo beginner_Tutorials-07 ROS话题 我使用的虚拟机软件:VMware Workstation 11 使用的Ubuntu系统:Ubuntu 14.04.4 LT ...

  4. 如何利用jQuery post传递含特殊字符的数据【转】

    在jQuery中,我们通常利用$.ajax或$.post进行数据传递处理,但这里通常不能传递特殊字符,如:“<”.本文就介绍如何传递这种含特殊字符的数据. 1.准备页面和控制端代码 页面代码如下 ...

  5. MVC4升级到MVC5未能加载文件或程序集System.Web.WebPages.Razor, Version=3.0.0.0

    首先,我并没有升级他,头一天还是好好的,用的都是2.0.0.0版本的,今天来打开就出现了这个错误: 未能加载文件或程序集“System.Web.WebPages.Razor, Version=3.0. ...

  6. Golang之时间格式化,计时器

    地鼠敲下一堆代码,记录着当天的时间 package main import ( "fmt" "time" ) func getTime() { now := t ...

  7. 766A Mahmoud and Longest Uncommon Subsequence

    A. Mahmoud and Longest Uncommon Subsequence time limit per test 2 seconds memory limit per test 256 ...

  8. httpclient之基本类

    HttpHost类  主机类  主要属性有域名和端口. HttpRoute类  路由类  主要属性有targetHost(目标主要).proxyChain[]代理链 RouteTracker类  和H ...

  9. Android窗口背景的优化

    视图有背景,每个窗口也是有背景的.每一Activity是一个窗口,每一个Activity都有不同得背景.界面的绘画顺序如下:窗口——跟视图 ——子视图.当我们的跟视图已经覆盖了整个窗口的时候 ,程序还 ...

  10. ubuntu16下Elasticsearch5.1.1安装部署

    本人在安装es5.1.1版本时候整理的一些过程,参照了网上部分过程:其中过程中也出现一些其它问题,出现的问题和解决方案都整理在此文中. 1Elasticsearch5.1.1安装 到ES官网https ...