Angular6 学习笔记——指令

2023-11-13

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

系列目录

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

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

(3)内容投影, ViewChild和ContentChild

(4)指令

(5)路由

指令

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

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

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

  1. 组件 — 组件的特殊存在,拥有模板
  2. 结构型指令 — 通过添加和移除 DOM 元素改变 DOM 布局的指令,常用的有:*ngIf,*ngFor,ngSwitch
  3. 属性型指令 — 改变元素、组件或其它指令的外观和行为的指令,常用的有:NgClass,NgStyle

组件

在查看源代码,我们会发现这样的画面
在这里插入图片描述
所以说组件是继承指令的,只是它比较特殊,有模版
同样,因为组件继承指令,在下面属性型和结构型指令的一系列操作,在组件中都是可以实现的
但是因为指令的目的是为了复用,在组件中这样操作是达不到这个目的,所以强烈不推荐这样去操作.
这里就不多做说明,有兴趣可以自己尝试一下

属性型指令

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

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

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

  1. 导入 Directive 装饰器(而不再是 Component)。
  2. 导入符号 Input、TemplateRef 和 ViewContainerRef,视指令类型与需求来选择
  3. 给指令类添加装饰器。
  4. 设置 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 [ngIf]="bool">
   <div class="name">{{hero.name}}</div>
 </ng-template>

指令
是一个 Angular 元素,用来渲染 HTML。 它永远不会直接显示出来。 事实上,在渲染视图之前,Angular 会把 及其内容替换为一个注释。如果没有使用结构型指令,而仅仅把一些别的元素包装进 中,那些元素就是不可见的。

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

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

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

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

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

 <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 生成的 元素中创建一个内嵌的视图,并把这个视图插入到一个视图容器中.可以使用TemplateRef取得 的内容,并通过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自带的有许多内置的指令,下面可以看见许多熟悉的身影:

在这里插入图片描述

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

(终)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • CentOS下安装好python和opencv,却import cv2失败

    在安装好CentOS和OpenCV后 在终端输入python 在输入import cv2 却报错 ImportError Mo module named cv2 浏览Python下文件夹发现cv2 so 原因是没有添加相应路径 解决办法 1
  • cookie及正则总结

    cookie及正则总结 cookie cookie是什么 cookie是存在浏览器上的一个只有4kb的容器 里面存储的类型为string 他会在每次http请求的时候 携带过去 他是为了解决http的无状态的特性 cookie的获取 doc
  • Java解析省市县树形结构工具类

    这篇博客将介绍如何根据6位行政编码 解析出省市县区等 adcode共6位 前俩位省 直辖市 自治区 前4位城市 6位区县 并优雅的树形结构输出省市 本文只解析了俩层 感兴趣的小伙伴可以自行解析区县 1 效果图 优雅的树形结构输出省市 22
  • 常见异常【一】TooManyResultsException

    org apache ibatis exceptions TooManyResultsException Expected one result or null to be returned by selectOne but found 1
  • Vercel和Railway都是云端的平台即服务提供商

    Vercel是一个专注于构建响应快速的现代网站和应用程序的服务平台 它被广泛用于构建静态网站 React应用程序等 Vercel提供全球CDN 构建和部署等强大的功能 支持多种前端框架 此外 Vercel还具有可扩展性 安全性和易用性 可以
  • Junit mock String authToken = request.getHeader(AUTH_TOKEN)

    单元测试 mock String authToken request getHeader AUTH TOKEN 代码示例 String authToken request getHeader AUTH TOKEN TEST示例 Mock M
  • 摸鱼,我是认真的

    苏生不惑第370 篇原创文章 将本公众号设为星标 第一时间看最新文章 今天分享几个有趣好玩的摸鱼网站 app 摸鱼 我是认真的 童年游戏博物馆 这个网站收录了各种童年记忆游戏 冒险岛 超级马里奥等 https www return8090
  • 港中文&商汤提出SMCA:用于DETR快速收敛的空间调制协同注意力

    为了加速DETR收敛 本文提出了一种简单而有效的方案来改进DETR框架 即空间调制协同注意 SMCA 机制 即插即用 让DETR涨点明显 性能优于可变形DETR DETR等网络 注1 文末附 Transformer 和 目标检测 交流群 注
  • VS2013+QT5.8.0配置

    一 安装 因为最近在看图形学的三维重构 需要学习meshlab的一些重建方法 官网找到了编译源码 需要编译 不得不学一下QT 先说说VS2013 QT的配置吧 系统环境 windows10 64bit VS 2013 QT5 8 0 QT5
  • Vue使用axios发送post请求,后端无法接收怎么处理?(Djnago后台)

    今天终于解决了一个困扰很久的问题 在使用Vue进行前端项目的搭建时 通常采用axios作为数据传输的工具 我们会发现 使用get请求一切都正常 但是使用post请求 会发生一些奇怪的事情 这次我使用的是python的web框架django
  • C#开发物联网实践(新手)之门槛

    ABP Cli安装问题 问题描述 想在VS2019上装CLI 输入 dotnet tool install g Volo Abp Cli 结果要求我下载VS2022 刚出的2022VS 我刚看完视频下载的VS2019 解决方法 下载国内版
  • vue教程

    原文 1 vue安装 1 1 直接用 script标签引入 对于制作原型或学习 你可以这样使用最新版本 对于生产环境 我们推荐链接到一个明确的版本号和构建文件 以避免新版本造成的不可预期的破坏 1 2 NPM创建 安装vue npm ins
  • 第14.6节 使用Python urllib.request模拟浏览器访问网页的实现代码

    Python要访问一个网页并读取网页内容非常简单 在利用 第14 5节 利用浏览器获取的http信息构造Python网页访问的http请求头 的方法构建了请求http报文的请求头情况下 使用urllib包的request模块使得这项工作变得
  • 人工智能+物联网+机器人 = AIOTBOT

    借着2019年人工智能 物联网 AIOT 的大潮 我辈机器人是否也能顺势而举 人工智能 物联网 机器人的融合缩写为 AIOTBOT
  • soap development issue

    description No Deserializer found to deserialize a xxx using encoding style yyy reason the requesting envelope xml doesn
  • Flutter 状态栏图标颜色方案

    方案一 使用 AppBar 配置 文章目录 方案一 使用 AppBar 配置 方案二 通过 AnnotatedRegion 控制 注意点 在 AppBar 中配置属性 brightness 其取值 Brightness dark AppBa
  • python如何输出一个数组_python中实现将多个print输出合成一个数组

    python中实现将多个print输出合成一个数组 比如有下面一段代码 for i in range 10 print s f list i name 该代码段的执行 会生成如下的10行 name 属性的字符串 f1 f2 f3 f4 f5
  • 根据请求动态设置 @Value 注入的属性值

    先说一下可以使用的场景 项目中有一些功能类使用了 Value修饰 这种属性取值通常要么是读取 yml 的配置文件 要么是读取配置中心 在我们在本地调试的时候Controller时 如果 如果Service层用到了 Value修饰 的属性时
  • JMeter:使用Docker进行分布式负载测试

    概述 单个的JMeter实例可能无法生成足够的负载来对应用程序进行压力测试 如本网站所示 一个JMeter实例将能够控制多个远程JMeter实例 并在你的应用程序上产生更大的负载 JMeter使用Java RMI Remote Method
  • Angular6 学习笔记——指令

    angular6 x系列的学习笔记记录 仍在不断完善中 学习地址 https www angular cn guide template syntax http www ngfans net topic 12 post 2 系列目录 1 组