一、组件模版
(一)数据绑定
-
用法
根据数据渲染模版内容<h1>{{message}}</h1> <h1>{{getInformation()}}</h1> <h1>{{a == b ? 'true' : 'false'}}</h1> <h1>{{'字符串'}}</h1> <h1 [innerHTML]="content"></h1>
-
容错处理
当模版使用的数据层级比较深的时候,如果某一层是可选的,这是就需要做容错处理。
组件类中:
Person
类的task
属性是可选的interface Person { name: string; age: number; task?: Task; } interface Task { name: string; } @Component({ selector: 'app-layout', templateUrl: './layout.component.html', }) export class LayoutComponent { public zs:Person = { name: 'zs', age: 18 } }
组件模版中:
- 使用
*ngIf
判断task属性是否存在,如果不存在不会渲染这个h1标签 - 使用安全操作符,如果不存在会有一个空的h1标签
<h1>{{zs.name}}</h1> <h1 *ngIf="zs.task">{{zs.task.name}}</h1> <h1>{{zs.task?.name}}</h1>
- 使用
(二)属性绑定
- 普通属性绑定
- 给DOM对象绑定
<h1 [innerHTML]="content"></h1>
- 给html标记绑定。自定义属性
<h1 [attr.data-test]="a">omg</h1>
- 类名绑定
- 可以根据数据一次设定一个,也可以批量设定
<h1 [class.active]="active">hhhhh</h1> <h1 [ngClass]="{'active':active,'error':error}">lllll</h1>
- 样式绑定
- 可以通过
[style.属性名]
加上具体的属性,也可以属性绑定一个数据源中的对象
<h1 [style.color]="active?'red':'blue'">style</h1> <h1 [ngStyle]="styleObj">stylesadasdsd</h1>
- 可以通过
(三)事件绑定
<button (click)="handleClick($event)">按钮</button>
<!--使用事件修饰符-->
<input (keyup.enter)="enter()">
(四)获取原生DOM对象
- 在组件模版中获取,使用#标识元素,并且传递到函数中
<button (click)="handleClick(btn)" #btn>按钮</button>
- 使用ViewChild获取一个元素
-
组件模版:
<p #myP>hello</p>
-
组件类:
import {AfterViewInit, Component, ElementRef, ViewChild} from '@angular/core'; @Component({ selector: 'app-layout', templateUrl: './layout.component.html', }) export class LayoutComponent implements AfterViewInit{ //使用ViewChild获取,然后创建变量myP并且赋值,然后进行类型声明 @ViewChild("myP") myP:ElementRef|undefined; ngAfterViewInit(): void { // 组件视图初始化完成之后的生命周期函数 console.log(this.myP?.nativeElement) } }
- 使用ViewChildren获取一组元素
- 组件模版:
<ul> <li #items>1</li> <li #items>2</li> <li #items>3</li> <li #items>4</li> </ul>
- 组件类:
import {AfterViewInit, Component, ElementRef, QueryList, ViewChildren} from '@angular/core'; @Component({ selector: 'app-layout', templateUrl: './layout.component.html', }) export class LayoutComponent implements AfterViewInit{ @ViewChildren('items') items: QueryList<HTMLLIElement> | undefined; ngAfterViewInit(): void { // 组件视图初始化完成之后的生命周期函数 // QueryList对象有一个_result属性,里面存储的是element list,但是不能直接获取,只能使用toArray转换为数组 console.log(this.items?.toArray()); } }
(五)双向数据绑定
双向数据绑定应用于表单元素
Angular将双向数据绑定的功能放在了@angular/forms里面
- 需要在module中引入FormsModule
- 在组件模版中的表单元素上使用
[(ngModel)]
<input type="text" [(ngModel)]="value"/>
<h1>{{value}}</h1>
<button (click)="value='hello'">click</button>
- 在组件类中初始化
value
数据
export class LayoutComponent{
public value: string = '';
}
(六)内容投影
类似于Vue中的组件插槽,子组件中的内容不是定义的时候就写好的,而是由父组件传递进去的。内容投影使用ng-content
标签标识。ng-content
起到占位的作用。分为两种情况:
- 父组件向子组件传递一块内容
- 父组件模版:
<app-bootstrap-panel> <div>向子组件传递过去的内容</div> </app-bootstrap-panel>
- 子组件模版:
<ng-content></ng-content>
- 父组件向子组件传递多块内容
-
父组件模版:
<app-bootstrap-panel> <div class="a">我是a</div> <div id="b">我是b</div> </app-bootstrap-panel>
-
子组件模版:
select使用css选择器选中父组件传递过来的元素,填充到对应位置<div style="color:red"> <ng-content select=".a"></ng-content> </div> <div style="color:blue"> <ng-content select="#b"></ng-content> </div>
-
页面效果:
在填充的过程中,ng-content标签会被对应的父组件传递过来的标签所代替。
如果不想要这个额外的div,只想要里面的内容,可以使用ng-container标签
父组件模版:<app-bootstrap-panel> <ng-container class="a">我是a</ng-container> <ng-container id="b">我是b</ng-container> </app-bootstrap-panel>
HTML渲染出来的结构:
(七)引入ng-bootstrap
- 下载
ng-bootstrap
ng add @ng-bootstrap/ng-bootstrap
此命令顺便安装好了bootstrap依赖,如果没有需要手动安装
在angular.json
中也自动引入boostrap
的样式文件
- 在模块中引入
ng-bootstrap
- 在模块中
- 在该模块的组件中使用,就不需要在引入模块了,具体代码从官网拖拽即可。官网给出的例子使用的是独立组件即组件的属性
standalone: true
,后续再进行探究。
ng-bootstrap在组件中使用
- 在模块中
二、指令Directive
指令是Angular提供的用来操作DOM的途径,指令分为属性指令和结构指令
- 属性指令:修改现有元素的外观或行为,给DOM元素设置属性,比如
innerHTML
,使用[]
包裹,不会增加或删除DOM - 结构指令:通过逻辑判断来增加、删除DOM节点以修改布局,使用*作为指令前缀
(一)内置指令
-
*ngIf
<!--用法一:根据条件决定判断决定是否渲染当前DOM--> <div *ngIf="true">ngIf里面的条件判断为真</div> <!--用法二:根据条件判断决定渲染哪一个指定的DOM,为true时加载then指定的DOM,为false时加载else指定的DOM--> <!--必须使用ng-template标签才能识别--> <div *ngIf="true;then data else noData"></div> <ng-template #data> <p>ngIf里面的条件判断为真</p> </ng-template> <ng-template #noData> <p>ngIf里面的条件判断为假</p> </ng-template>
条件判断为false时不会创建DOM元素
-
[hidden]
根据条件判断决定是否隐藏元素,为true时隐藏,为false时不隐藏<div [hidden]="false">不隐藏</div> <div [hidden]="true">隐藏</div>
控制display属性是否为none,隐藏时也会创建DOM元素
-
*ngFor
- 基本用法
index:获取索引
even:当前元素索引是不是偶数
odd:当前元素索引是不是奇数
first:当前元素是不是第一个
last:当前元素是不是最后一个
<ul> <li *ngFor=" let user of users; let i = index; let isEven = even; let isOdd = odd; let isFirst = first; let isLast = last" > ({{i}}) {{user.name}} </li> </ul>
-
高级用法 *ngFor可以使用trackBy去追踪每一个元素,先说具体用法:
组件模版中<ul> <li *ngFor="let user of users"> {{user.name}} </li> </ul> <!--使用trackBy--> <div *ngFor="let item of users; trackBy: trackByItems"> ({{item.id}}) {{item.name}} </div> <!--调用重新赋值的方法--> <button (click)="changeUser()">修改数组</button>
组件类中:
public users:User[] = [ {id: 1, name: 'John'}, {id: 2, name: 'Mary'}, {id: 3, name: 'Steve'}, {id: 4, name: 'Jane'}, ] // 重新给users赋值 changeUser(){ this.users = [ {id: 1, name: 'John'}, {id: 2, name: 'Mary'}, {id: 3, name: 'Steve'}, {id: 4, name: 'Jane'}, {id: 5, name: 'Tom'} ] } // 这个方法用来返回想要追踪的属性,可以是id,也可以是别的属性,最好是唯一标识 trackByItems(index: number, user: User): number { return user.id; }
在浏览器中运行,并且点击按钮,查看element的变化:
可以看到,不使用trackBy
的*ngFor
数组的每一项对应的元素都被重新创建了,而使用trackBy
的*ngFor
只有真正发生改变的那一项发生了重新渲染。默认Angualr会将数组作为一个整体,重复赋值时会整体销毁重建;而使用trackBy
,Angular就可以可以追踪每一个元素,数组重新赋值时对比每一项的变化,只会重复创建有修改的项,起到节省性能的作用。
(二)自定义指令
-
创建自定义指令
使用Angular-cli提供的命令:ng g d directives/directiveDemo1
Angular会在相应的位置创建一个ts文件,并且在根模块中引入这个指令
指令文件:import { Directive } from '@angular/core'; @Directive({ selector: '[appDirectiveDemo1]' // 通过属性的方式使用 }) export class DirectiveDemo1Directive { constructor() { } }
根模块:
指令跟组件一样,必须属于某一个模块才能正常工作 -
使用自定义指令
- 在根模块的模版文件中,在HTML元素上通过属性的方式使用自定义指令:
<div appDirectiveDemo1>使用自定义指令</div>
- 在指令内部获取当前DOM元素,有几点需要注意:
1. 需要引入ElementRef服务,并且传递到constructor的形参中
2. 在构造函数中根据参数进行数据初始化
3. 操作DOM需要在AfterViewInit
生命周期中,此时视图已经完成了初始化import {AfterViewInit, Directive, ElementRef } from '@angular/core'; @Directive({ selector: '[appDirectiveDemo1]' // 通过属性的方式使用 }) export class DirectiveDemo1Directive implements AfterViewInit { public element: HTMLElement; constructor(private elementRef: ElementRef) { this.element = elementRef.nativeElement; } ngAfterViewInit() { console.log(this.element); this.element.innerHTML = 'Hello World'; } } ```
- 查看页面效果:
- 向自定义指令中传递数据
- 模版组件中使用
[]
传递数据<div [appDirectiveDemo1]="{bgColor:'red'}">使用自定义指令</div>
- 指令中通过
@Input
装饰器,获取传递进来的数据,并且创建变量进行赋值,并且需要指定一个初始化的值// 定义Options接口,用于接收传入的参数 interface Options { bgColor?: string; } // ... export class DirectiveDemo1Directive implements AfterViewInit { @Input("appDirectiveDemo1") styleOptions: Options = {}; // ... }
- 给DOM元素绑定事件:鼠标移入字体变黄,鼠标移出变成默认颜色,如果没有指定默认颜色就变为skyblue色
给元素绑定事件需要使用@HostListener
装饰器// onMouseEnter:自定义的函数名 @HostListener('mouseenter') onMouseEnter() { this.element.style.color = 'yellow'; } // onMouseLeave:自定义的函数名 @HostListener('mouseleave') onMouseLeave() { this.element.style.color = this.styleOptions.bgColor || 'skyblue'; }
- 基本用法