当前位置: 首页 > news >正文

[Angular 基础] - 指令(directives)

[Angular 基础] - 指令(directives)

这里假设已经知道如何创建 Angular 组件以及数据绑定,不然可以参考前两篇笔记:

  • [Angular 基础] - Angular 渲染过程 & 组件的创建

  • [Angular 基础] - 数据绑定(databinding)

就像中文翻译一样,directives 就是指令,它就是一系列 DOM 中存在的指令

component directive

Component 这个 declaration 就是一个最基础的指令,当运行:

import { Component } from '@angular/core';@Component({selector: 'app-my-component',template: `<p>Hello, world!</p>`,
})
export class MyComponent {}

这段代码的时候,其实就已经是在运行一个指令,这个指令做了下面几件事情:

  • @Component 表明下面声明的类是一个组件
  • selector 定义一个元素,该元素会接受当前组件内的 HTML Template
  • template 定义一个 HTML Template,将会展现在 app-my-component 这个 HTML 元素中

这就是当前需要遵从的指令,我个人理解是通知 DOM 需要渲染哪个对应的 HTML Template

以此类推,@NgModule, @Directive 等也是对应的 component directive

structural directives

structural directives 的指令是通知 DOM 增加或删除特定的 HTML 元素。目前主流的内置 structural directives 有 3 个:*ngIf, *ngFor*ngSwitch,当然,这不代表 Angular 之提供了这三个 structural directives

除此之外,开发者自己也可以创建相应的 structural directives

*ngIf

语法为 *ngIf="expression",并且这个表达式(expression) 需要返回一个 boolean。依旧使用之前的案例,这里假设点击 add server 的按钮会实现对应功能,并且需要向用户显示新的组件已经生成

对应的 View 层修改如下:

<!-- 其余显示添加 server 的 input 和 button 这里不重复了 -->
<p *ngIf="serverCreated">Sever was created, server name is {{ serverName }}</p>

对应的 VM 层修改如下:

// 新增加的变量,只有在用户点击创建 server 的 btn 时才需要显示信息serverCreated = false;onCreateServer() {this.serverCreationStatus = 'Server was created!';this.serverCreated = true;}

效果如下:

在这里插入图片描述

可以看到只有当 *ngif 里的条件为 true 时,该 DOM 才会渲染

有了 if 也会有 else 条件,这时候 V 层的代码可以这么修改:

<p *ngIf="serverCreated; else noServer">Sever was created, server name is {{ serverName }}
</p>
<ng-template #noServer><p>No server was created!</p>
</ng-template>

这里使用了一个特殊的 HTML 元素——ng-template,它主要的用途是为了搭配 structural directives 去使用的;这里 #noServer 是对 ng-template 这一元素的引用变量名

*ngIf v17 的更新

目前有一个新的语法可以重置 ngIf,它的语法就是 @for,使用方式如下:

@if (serverCreated) {
<p>Sever was created, server name is {{ serverName }}</p>
} @else {
<p>No server was created!</p>
}

其展示的效果是一样的,else if 的语法则为 @else if

这个语法是 v17 最新推出的版本,暂时还不是 production-ready,所以只在这里提一下,不会深入研究

ngFor

这是一个可以循环渲染 HTML 元素的方式,用法如下:

  • 修改 VM 层

    这里会新增一个 servers 的数组,并且在 onCreateServer 中将新添的 serverName 推到数组中去:

    servers = ['Test Server', 'Test Server2'];onCreateServer() {this.serverCreationStatus = 'Server was created!';this.servers.push(this.serverName);this.serverCreated = true;
    }
    
  • 修改 V 层

    这里就使用 *ngFor 去渲染整个数组:

    <app-server *ngFor="let server of servers"></app-server>
    

最终效果如下:

在这里插入图片描述

⚠️:这里还没有涉及到组件之间数据的传输,所以 serverName 不会动态渲染

相比较 ngIfngFor 的语法更复杂一些,它的完整语法如下:

<div*ngFor="let item of servers;trackBy: trackByFn;index as i;first as isFirst;last as isLast;even as isEven;odd as isOdd"
>{{ i }}: {{ item }}<span *ngIf="isFirst">(first)</span><span *ngIf="isLast">(last)</span><span *ngIf="isEven">(even)</span><span *ngIf="isOdd">(odd)</span>
</div>

其中 trackByFn 写在了 VM 层:

  trackByFn(index: number, item: string) {return item;}

最终展现的效果如下:

在这里插入图片描述

这里的 trackBy: trackByFn; 是 Angular 提出的一个优化方案,当它存在的时候,Angular 会检查当前返回值是否变更,如果不变更的话将不会重新渲染当前的 DOM 结点

至于 first, last 这四个是 Angular 提供的值,以便可以轻松检查这些边界条件

*ngFor v17 的更新

这个语法如下:

@for (item of items: track item.id) {
<li>{{ item.title }}</li>
}

这个语法是 v17 最新推出的版本,暂时还不是 production-ready,所以只在这里提一下,不会深入研究

ngSwitch

它的语法则类似于 switch,修改的代码如下:

<div*ngFor="let item of servers;trackBy: trackByFn;index as i;first as isFirst;last as isLast;even as isEven;odd as isOdd"
>{{ i }}: {{ item }}<span *ngIf="isFirst">(first)</span><span *ngIf="isLast">(last)</span><span *ngIf="isEven">(even)</span><span *ngIf="isOdd">(odd)</span><div [ngSwitch]="item"><p *ngSwitchCase="'red'">You picked red server!</p><p *ngSwitchCase="'blue'">You picked blue server!</p><p *ngSwitchCase="'green'">You picked green server!</p><p *ngSwitchDefault>Pick a server name</p></div>
</div>

效果如下:

在这里插入图片描述

*ngSwitch v17 的更新

这个语法如下:

@switch (expression) { @case value1:
<p>value1</p>
@case value2:
<p>value2</p>
}

这个语法是 v17 最新推出的版本,暂时还不是 production-ready,所以只在这里提一下,不会深入研究

attribute directives

structural directives 控制的是 DOM 元素的增删(是否渲染),那么 attribute directives 控制的则是渲染 DOM 中的属性

这里也会列举主流用的 3 个,同样,这也不代表 Angular 仅仅提供了这 3 个 structural directives,而且开发者同样也可以创建自己的 structural directives

ngModel

这个在之前的笔记里已经提过了,NgModel 主要提供的是双向绑定的功能

ngStyle

ngStyle 就是比较简单的控制 CSS 的地方,用法如下:

<p[ngStyle]="{'background-color': serverStatus === 'offline' ? 'red' : 'green'}"
>{{ "Server" }} with ID {{ serverId }} is {{ getServerStatus() }}
</p>

效果如下:

在这里插入图片描述

⚠️:以上代码修改在 server.component.html

❗:如果无法正确渲染,请查看 servers.component.html 中的 ngFor 是不是返回 <app-server></app-server>

⚡:ngStyle 是 attribute directives,[ngStyle] 则是使用了 property binding

🛣️:'backgound-color' 还有另一个写法是用驼峰命名法 backgroundColor,而 : 后面的也只是需要一个表达式,这里用了三元式,也可以单独创建一个方法

ngClass

这个指令则是动态更新类名,这里实现代码如下:

<p[ngStyle]="{'background-color': serverStatus === 'offline' ? 'red' : 'green'}"[ngClass]="{online: serverStatus === 'online',offline: serverStatus === 'offline'}"
>{{ "Server" }} with ID {{ serverId }} is {{ getServerStatus() }}
</p>

至于 VM 层也需要添加对应的 CSS:

@Component({selector: 'app-server',templateUrl: './server.component.html',styles: [`.online {color: cyan;}.offline {color: lightgray;}`,],
})
export class ServerComponent {}

最终效果如下:

在这里插入图片描述

总结

下面都是个人理解,对我来说 directives 解决的是下面的问题:

在这里插入图片描述

  • component directive

    • what

      其实也可以用 which 代替,目前接触过的有两个 directives:

      • @Component 来说是哪个 HTML Template

      • @NgModule 是哪个对应的 NgModule

    • where

      这个目前接触到的是 @Component 中的 selector,这里决定哪里会渲染对应的指代组件

  • structural directive

    这个可以解决一个 when 的问题,即什么情况下会渲染对应的组件

    if/elseswitchfor 循环,都是在满足一定条件下才会渲染对应的组件

  • attribute directive

    这个则是解决了一个 how 的问题,即如何渲染对应组件

    ngModel 的双向绑定,ngClass 的添加对应类,ngStyle 的对应样式,都可以满足一个 how 的问题

相关文章:

  • 精灵图,字体图标,CSS3三角
  • vue项目打包部署到flask等后端服务里面,实现前后端不分离部署,解决空白页面和刷新页面not fount问题
  • 【ES数据可视化】kibana实现数据大屏
  • MySQL篇----第十八篇
  • 任意IOS16系统iPad/Iphone开启台前调度
  • P1028 [NOIP2001 普及组] 数的计算题解
  • 计算机网络基本知识(二)
  • 相机图像质量研究(7)常见问题总结:光学结构对成像的影响--镜片固化
  • C++ //练习 5.5 写一段自己的程序,使用if else语句实现把数字成绩转换成字母成绩的要求。
  • hook函数——useRef
  • LabVIEW工业监控系统
  • 【Linux】Ubuntu 22.04 升级 nodejs 到 v18
  • 伪装成NodeJS的勒索病毒,勒索呼伦贝尔的空气
  • Linux运行级别 | 管理Linux服务
  • 【Linux系统学习】2.Linux基础命令
  • CAP 一致性协议及应用解析
  • egg(89)--egg之redis的发布和订阅
  • golang 发送GET和POST示例
  • JavaScript HTML DOM
  • JS函数式编程 数组部分风格 ES6版
  • log4j2输出到kafka
  • Node 版本管理
  • vue自定义指令实现v-tap插件
  • Webpack入门之遇到的那些坑,系列示例Demo
  • windows下如何用phpstorm同步测试服务器
  • 闭包,sync使用细节
  • 纯 javascript 半自动式下滑一定高度,导航栏固定
  • 反思总结然后整装待发
  • 分类模型——Logistics Regression
  • 高程读书笔记 第六章 面向对象程序设计
  • 力扣(LeetCode)56
  • 模仿 Go Sort 排序接口实现的自定义排序
  • 入职第二天:使用koa搭建node server是种怎样的体验
  • 什么软件可以剪辑音乐?
  • Oracle Portal 11g Diagnostics using Remote Diagnostic Agent (RDA) [ID 1059805.
  • k8s使用glusterfs实现动态持久化存储
  • Play Store发现SimBad恶意软件,1.5亿Android用户成受害者 ...
  • 摩拜创始人胡玮炜也彻底离开了,共享单车行业还有未来吗? ...
  • ​Java并发新构件之Exchanger
  • ​第20课 在Android Native开发中加入新的C++类
  • # 数据结构
  • #1014 : Trie树
  • (11)工业界推荐系统-小红书推荐场景及内部实践【粗排三塔模型】
  • (2)MFC+openGL单文档框架glFrame
  • (java)关于Thread的挂起和恢复
  • (vue)页面文件上传获取:action地址
  • (个人笔记质量不佳)SQL 左连接、右连接、内连接的区别
  • (七)Knockout 创建自定义绑定
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • (转)setTimeout 和 setInterval 的区别
  • (转贴)用VML开发工作流设计器 UCML.NET工作流管理系统
  • .axf 转化 .bin文件 的方法
  • .NET CF命令行调试器MDbg入门(二) 设备模拟器
  • .net 简单实现MD5
  • .netcore 6.0/7.0项目迁移至.netcore 8.0 注意事项