这里的ng
并非电影电视中导演说太烂、要再拍一次的NG(No Good),
而是指Angular的ng。
Angular中的Directive
直接翻译是指令、指示,
我个人比较喜欢指示、指引的翻译,代表Angular看到这个特别的词,要去做对应的事情或动作。
指令比较像在Terminal上做的输入。
Angular中的Directive分成以下三种:
Component Directive
Attribute Directive
Structure Directive
这几样都是在样板(.html档案)中会看到的、HTML看不懂的东西,
是专门给Angular看的。
什麽是元件型指示?
指的就是元件啦!
ex: <app-root>
、<app-component>
含有样板的指示,以标签(tag)形式呈现
什麽是属性型指示?
指的就是属性、样式啦!
修改套用该属性的元素外观、样式、行为
属性型指令有以下三种:
ngStyle
ngClass
ngModel
可以使用任意的CSS,搭配ngStyle动态的来修改Style
HTML
<div class="container">
<h1 [ngStyle]="{'font-size': 26 + counter + 'px'}">{{counter}}</h1>
<input type="button" value="计数器+按了会变大" (click)="count()">
</div>
TS
...
export class AppComponent {
counter = 0;
count(){
this.counter++;
}
}
也可以将Style变成一个方法(method),并移进TS中,透过点击事件触发
HTML
<div class="container">
<h1 [ngStyle]="getStyle()">{{counter}}</h1>
<input type="button" value="计数器+按了会变大" (click)="count()">
</div>
TS
export class AppComponent {
counter = 0;
count(){
this.counter++;
}
getStyle(){
return {('font-size': 26 + this.counter) + 'px'};
}
}
动态样式套用
甚至有更简便不需要ngStyle的写法
HTML
<div class="container">
<h1 [style.font-size]="(26+counter)+'px'">{{counter}}</h1>
<input type="button" value="计数器+按了会变大" (click)="count()">
</div>
如果要用[style]
写死固定数值的话,
要额外加上一个双或单引号,使他变成一个JS物件,
算是比较特别的用法。
HTML
<div class="container">
<h1 [style.color]="'green'">标题</h1>
</div>
动态套用class
藉由带入布林值,让符合条件值时动态新增class、不符合时则移除
[class.classname]="true"
HTML
<div class="container">
<h1 [style.font-size]="(26+counter)+'px'" [style.color]='"green"'>{{counter}}</h1>
<input type="button" value="计数器+按了会变大" (click)="count()">
<p [ngClass]="{highlight: counter % 2 == 0}">偶数时会有萤光背景</p>
</div>
CSS
.highlight{
background: yellow;
}
也可以改成简短一点
HTML
<p [class.highlight]="counter % 2 == 0">偶数时会有萤光背景</p>
[(ngModel)] = 'property'
就是前一篇提到的双向系结。
什麽是结构型指示?
指的就是会影响到程序流的指令啦!
可以新增、删除DOM元素来动态改变DOM结构
结构型指令有以下三种:
ngIf
ngSwitch
ngFor
符合条件时会动态新增DOM、不符条件时动态移除(是移除而非隐藏)
若该元素被移除,若元素里面有其他的tag或directive 也会一并被移除。
斩草除根。
HTML
<p *ngIf="counter % 2 == 0">偶数时整个DOM会被移除</p>
HTML
<div class="container">
<h1 [style.font-size]="(26+counter)+'px'" [style.color]='"green"'>{{counter}}</h1>
<input type="button" value="计数器+按了会变大" (click)="count()">
<div [ngSwitch]="counter % 3">
<div *ngSwitchCase="1"><p>3N+1</p></div>
<div *ngSwitchCase="2"><p>3N+2</p></div>
<div *ngSwitchDefault><p>Default 三的倍数</p></div>
</div>
</div>
switch在条件多时非常好用,
但好用归好用,为了要用switch而一下子多出了两层div,会造成网页架构跑版、跟原本预期不同
这时可将<div>
改为<ng-container>
,就不会产生任何的HTML标签。
*ngFor="let item of list"
只能带入list、set进行迭代,
我们先来产生一些学生姓名与分数的资料
TS
export class AppComponent {
data = [
{SID: 'S001', name: '王大明', score: 80, 'image-url': 'https://picsum.photos/id/10/200/300', 'self-intro': '<div>大家好,我是王大明。</div>'},
{SID: 'S002', name: '林一二', score: 99, 'image-url': 'https://picsum.photos/id/20/200/300', 'self-intro': '<div>大家好,我是林一二<br>请各位多多指教。</div>'},
{SID: 'S003', name: '黄阿道', score: 54, 'image-url': 'https://picsum.photos/id/30/200/300', 'self-intro': '<div>大家好,我是黄阿道<br>我成绩不太好<br>请大家多包涵。</div>'},
];
set = new Set([1, 1, 2, 3, 4, 5, 5, 5]);
}
透过取得TS里的变数资料,自动产生重复性的结构
取得Set资料
HTML
<div class="container" *ngFor="let item of set;">
<p>{{item}}</p>
</div>
取得List资料
HTML
<div class="container d-flex">
<div class="student border border-dark m-5" id="student0" *ngFor="let item of data">
<p>学号: {{item.SID}}</p>
<p>姓名: {{item.name}}</p>
<img [src]="item['image-url']" alt="大头照">
<p>分数: {{item.score}}</p>
<p class="self-intro" [innerHTML]="item['self-intro']"></p>
</div>
</div>
要取用
image-url
或self-intro
资料时,没办法直接透过.
来取得item
底下的物件,
只能透过item['image-url']
带入Key来取值。另外,
因为TS变数资料中的self-intro
是HTML结构,
为了正常显示出文字而用了属性系结在innerHTML属性上。
如果要让id也跟着做变化,除了透过带入学号 id="{{item.SID}}"
以外,
也可带入for回圈中的index值 let item of data; let i=index
。
这边可导出的变数index只能在ngFor
里面可使用,所以需要使用区域变数let来宣告值,让i
可在for回圈中使用。
NgForOf provides exported values that can be aliased to local variables
HTML
<div class="student border border-dark m-5" id="student{{i}}" *ngFor="let item of data; let i=index">
另外在资料中多加一个人物叫hacker,填入一些恶意程序码
Angular会过滤掉JS程序码而不执行、预防XSS攻击
TS
{SID: 'S999', name: 'Hacker', score: 1000000, 'image-url': 'https://picsum.photos/id/444/200/300', 'self-intro': '塞JS脚本<br><script>alert("hi");</script>'}
克难的做法:
透过pipe管线与ngFor,不写任何TS逻辑,在HTML中使用for迭代印出物件
资料共八笔,每一排会呈现两笔,共印了四排,但因为迭代的关系总共跑了八次回圈
(通常会在TS里面先做处理、不会这样子写)
HTML
<div class="container" *ngFor="let _ of list; let len = count; let count = index">
<div>>>>第{{count+1}}次回圈</div>
<div *ngFor="let item of list | slice:count*2:count*2+2">
<span>{{item}}</span>
</div>
<br>
</div>
TS
export class AppComponent {
list = [
'1',
'22',
'333',
'4444',
'55555',
'666666',
'7777777',
'88888888',
];
}
如果精准的控制for回圈次数,可搭配constructor
HTML
<div class="container">
<div *ngFor="let _ of [].constructor(10); let i = index">
{{i}}
</div>
</div>
当後端传送的API资料不一定有该物件时,
想读取有可能为undifined
、null
物件底下的值,又不希望因为取不到物件的值而让整篇页面挂掉。
(取到undifined、null物件都没事,有问题的是当尝试取undifined、null物件底下的child)
希望有则显示、没则忽略这个此不确定物件时,可以加上?.
安全导览运算子,
当遇到undifined、null物件的话,会直接return null
,而不会做尝试取值导致网页崩溃。
首先来改一下资料格式,
新增一个info
属性来包住原本的SID
、name
TS
export class AppComponent {
data = [
{info: {SID: 'S001', name: '王大明'}, score: 80, 'image-url': 'https://picsum.photos/id/10/200/300', 'self-intro': '<div>大家好,我是王大明。</div>'},
{info: {SID: 'S002', name: '林一二'}, score: 99, 'image-url': 'https://picsum.photos/id/20/200/300', 'self-intro': '<div>大家好,我是林一二<br>请各位多多指教。</div>'},
{info: {SID: 'S003', name: '黄阿道'}, score: 54, 'image-url': 'https://picsum.photos/id/30/200/300', 'self-intro': '<div>大家好,我是黄阿道<br>我成绩不太好<br>请大家多包涵。</div>'},
];
}
这边也相应修改一下取值方式
HTML
<div class="container d-flex">
<div class="student border border-dark m-5" id="student0" *ngFor="let item of data">
<p>学号: {{item.info.SID}}</p>
<p>姓名: {{item.info.name}}</p>
<img [src]="item['image-url']" alt="大头照">
<p>分数: {{item.score}}</p>
<p class="self-intro" [innerHTML]="item['self-intro']"></p>
</div>
</div>
到这边都没有问题。
但今天如果来了一个骇客,插入了一笔没有带info
物件的资料
从那笔资料开始後面都无法正常显示了
TS
export class AppComponent {
data = [
{info: {SID: 'S001', name: '王大明'}, score: 80, 'image-url': 'https://picsum.photos/id/10/200/300', 'self-intro': '<div>大家好,我是王大明。</div>'},
{score: 1000000, 'image-url': 'https://picsum.photos/id/444/200/300', 'self-intro': '塞JS脚本<br><script>alert("hi");</script>'},
{info: {SID: 'S002', name: '林一二'}, score: 99, 'image-url': 'https://picsum.photos/id/20/200/300', 'self-intro': '<div>大家好,我是林一二<br>请各位多多指教。</div>'},
{info: {SID: 'S003', name: '黄阿道'}, score: 54, 'image-url': 'https://picsum.photos/id/30/200/300', 'self-intro': '<div>大家好,我是黄阿道<br>我成绩不太好<br>请大家多包涵。</div>'},
];
}
此时只要在这info物件上加上?
,
就能忽略过没有带info
物件的那格资料栏位,
让後面的资料也能够继续显示
HTML
<p>学号: {{item.info?.SID}}</p>
<p>姓名: {{item.info?.name}}</p>
今天人还在外面游山玩水阿阿阿阿XDDD 来介绍一个比较无关资安与WEB技术, 纯粹是Burp Sui...
这次只有针对 RV31I 指令做解码, 原本希望能让这次加入的 INSTRUCTION_DECODE...
Tag:随意刷-[50-100] LeetCode Problem Source: 88. Merg...
本文将於赛後同步刊登於笔者部落格 有兴趣学习更多 Kubernetes/DevOps/Linux 相...
在每个要求你注册会员的新网站,都必须要想一组莫名复杂的密码,不但长度要够长、更要包含一堆有的没的字元...