1. angular组件
创建组件
使用 ng generate component <component-name> 创建的组件会自动生成再app.module中引用,推荐使用ng命令生成组件
快速创建
ng g c xxx
@Component({
selector: 'app-root', //这个css选择器用于再模板中标记出该指令,并触发该指令的实例化
standalone: true,
imports: [RouterOutlet],
templateUrl: './app.component.html', //组件模板文件的url
styleUrl: './app.component.less' //组件样式文件
})
新版本angular没有app.module.ts,引入组件方式如下:
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { HelloComponent } from './hello/hello.component' //在app.components.ts中引入
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet,HelloComponent], //通过imports引入后,页面app.components.html中就可以使用<app-hello><app-hello>
templateUrl: './app.component.html',
styleUrl: './app.component.less'
})
export class AppComponent {
title = 'my-app修改过';
}
ng new 不会在 src 根文件夹中生成 app.module.ts
需要使用 --no--standalone 来生成app.module.ts
使用以下命令生成具有 app.module.ts 和 app-routing.module.ts 的项目:
ng new my-app --no-standalone --routing --ssr=false
angular模板
在angular中,模板就是一块HTML,在模板中,你可以通过一种特殊语法来使用angular的许多功能
2. 插值语法
hello.components.ts创建
export class HelloComponent {
name:string = 'Tina'
}
hello.components.html中引用
{{ name }}
3.属性绑定
属性绑定使用的语法是[属性名]
<div [id]="'box'">属性绑定</div>
<div [id]="box">属性绑定</div>
<h3 [class.h3-dom]="true">单一类绑定</h3>
<h3 [class]="h3-dom title-dom min-title">多重类绑定</h3>
<h3 [class] = "{'h3-dom':true,'title-dom':false}">类名条件渲染</h3>
<h3 [class] = "['h3-dom','title-dom']">数组条件渲染</h3>
<h3 [style.color] = "'red'">单一样式绑定</h3>
<h3 [style]="'color:green; border:2px solid #000;'">多样式绑定</h3>
4.条件判断
<!-- 条件判断语法 -->
<div *ngIf="isMax">isMax == true</div>
<div *ngIf="!isMax">isMax == false</div>
<ng-template [ngIf]="isMax"><div>isMax == true</div></ng-template>
hello.components.ts中需要引入NgIf
import { NgIf } from '@angular/common';
import { Component } from '@angular/core';
@Component({
selector: 'app-hello',
standalone: true,
imports: [NgIf],
templateUrl: './hello.component.html',
styleUrl: './hello.component.less'
})
export class HelloComponent {
name:string = 'Tina'
box:string = 'box-dom'
isMax:boolean = true
}
<ng-container *ngIf="isMax; eles elseTemplate">
<div>isMax == true</div>
</ng-container>
<ng-template #elseTemplate>
<div>isMax == false</div>
</ng-template>
5.循环语句
<!-- 循环语句 -->
<!-- for -->
<div *ngFor="let color of colors let i=index let odd=odd">
{{odd}}
{{i}}
{{color}}
</div>
<!-- switch -->
<div [ngSwitch]="type">
<div *ngSwitchCase="1">type:1</div>
<div *ngSwitchCase="2">type:2</div>
<div *ngSwitchDefault>type!=1,2</div>
</div>
ts
import { NgFor, NgIf, NgSwitch, NgSwitchCase, NgSwitchDefault } from '@angular/common';
import { Component } from '@angular/core';
@Component({
selector: 'app-hello',
standalone: true,
imports: [NgIf,NgFor,NgSwitch,NgSwitchCase,NgSwitchDefault],
templateUrl: './hello.component.html',
styleUrl: './hello.component.less'
})
export class HelloComponent {
name:string = 'Tina'
box:string = 'box-dom'
isMax:boolean = false
colors:Array<string> = ['red','blue','yellow','green']
type:number=3
}
6.事件绑定
<!-- 事件绑定 (事件类型) = "执行函数" -->
<button (click)="clickFun($event)">点击</button>
<input type="text" (input)="inpChange($event)">
clickFun(e:Event){
console.log(111)
console.log(e)
}
inpChange(e:Event){
console.log(e)
console.log(e.target)
}
7.模板引用变量
模板变量可以帮助你在模板的另一部分使用这个部分的数据。使用模板变量,你可以执行某些任务,比如响应用户输入或微调应用的表单。在模板中,要使用井号#来生命一个模板变量。下列模板变量#userName在语法<input>元素上生命了一个名未userName的变量
<input #userName type="text" (input)="inpChange($event)">
<button (click)="getUserName(userName.value)">获取input值</button>
getUserName(v:string){
console.log(v)
}
8.数据双向绑定ngModel
<!-- 双向绑定 ngModel只对表单元素有效 -->
<input type="text" [(ngModel)]="title">
<p>title:{{title}}</p>
import { FormsModule} from '@angular/forms';
@Component({
selector: 'app-hello',
standalone: true,
imports: [
FormsModule
],
templateUrl: './hello.component.html',
styleUrl: './hello.component.less'
})
export class HelloComponent {
title:string = '1111'
}
9.动态表单控件
<!-- 动态表单控件 -->
<label for="">
年龄: <input type="text" [formControl] = 'age'>
</label>
<p>年龄: {{ age.value }}</p>
<button (click)="ageChangeFun()">修改年龄</button>
import { ReactiveFormsModule,FormControl } from '@angular/forms';
@Component({
selector: 'app-hello',
standalone: true,
imports: [
ReactiveFormsModule
],
templateUrl: './hello.component.html',
styleUrl: './hello.component.less'
})
export class HelloComponent {
age:FormControl = new FormControl('')
ageChangeFun(){
this.age.setValue(18)
}
}
10.动态表单控件组
<!-- 动态表单控件组 -->
<form action="" [formGroup]="loginForm">
<label for="">
账号:
<input type="text" formControlName="userName">
</label>
<br>
<label for="">
密码:
<input type="password" formControlName="passWord">
</label>
<br>
<button (click) = "subFormFun()">提交</button>
</form>
import {FormControl,FormGroup } from '@angular/forms';
export class HelloComponent {
loginForm = new FormGroup({
userName: new FormControl(''),
passWord: new FormControl('')
})
}
subFormFun(){
console.log(this.loginForm.value)
}
}
11.表单验证
表单元素添加required关键字表示必填,通过绑定ngModel的引用可以拿到当前组件的信息,通过引用获取到验证的信息
<!-- 表单验证 -->
<form action="">
账号: <input type="text" required #nameInp="ngModel" [(ngModel)]="formData.name" name="userName">
<br>
<!-- 验证结果 <span>{{ nameInp.valid }}</span> -->
<span *ngIf="!nameInp.valid">请输入账号</span>
<br>
密码: <input type="text" required #pasInp="ngModel" [(ngModel)]="formData.password" name="password">
<br>
<!-- 验证结果 <span>{{ pasInp.valid }}</span> -->
<span *ngIf="!pasInp.valid">请输入密码</span>
<br>
<button (click)="subFormFun()">提交</button>
</form>
formData = {
name:'',
password:''
}
12.自定义表单验证
<!-- 自定义表单验证 -->
<form action="" [formGroup]="valiDataForm">
<label for="">
账号:
<input type="text" formControlName="userName">
</label>
<p *ngIf="valiDataForm.get('userName')?.errors?.['required']">请输入账号</p>
<p *ngIf="valiDataForm.get('userName')?.errors?.['minlength'] || valiDataForm.get('userName')?.errors?.['maxlength']">账号长度在6-18之间</p>
<br>
<label for="">
密码:
<input type="password" formControlName="password">
</label>
<p *ngIf="valiDataForm.get('password')?.errors?.['desc']">{{ valiDataForm.get('password')?.errors?.['desc'] }}</p>
<br>
<label for="">
手机号:
<input type="number" formControlName="phone">
</label>
<p *ngIf="valiDataForm.get('phone')?.errors?.['desc']">{{ valiDataForm.get('phone')?.errors?.['desc'] }}</p>
<br>
<button (click) = "subvaliDataFormFun()">提交</button>
</form>
import {FormGroup,FormBuilder, Validators } from '@angular/forms';
export class HelloComponent {
valiDataForm:FormGroup
constructor(private B:FormBuilder){
this.valiDataForm = this.B.group({
userName:['',[Validators.required,Validators.maxLength(18),Validators.minLength(6)]],
password:['',[this.passWordVal]],
phone:['',[Validators.required,this.phoneVal]]
})
}
passWordVal(password:FormControl){
const value = password.value || ''
if(!value) return {desc:'请输入密码'}
const valid = value.match(/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,20}$/)
return valid? {} :{desc:'密码至少包含数字和英文,长度6-20'}
}
phoneVal(phone:FormControl){
const value = phone.value || ''
if(!value) return {desc:'请输入手机号'}
const valid = /^1(3[0-9]|5[0-3,5-9]|7[1-3,5-8]|8[0-9])\d{8}$/.test(value)
return valid ? {} : {desc:'请输入正确的手机号'}
}
subvaliDataFormFun(){
console.log(this.valiDataForm.get('userName'))
console.log(this.valiDataForm.get('password'))
console.log(this.valiDataForm.get('phone'))
}
}
13.Angular管道
管道的作用就是传输。不同的管道具有不同的作用。(其实就是处理数据)
pipe用法
{{ 输入数据 | 管道:管道参数 }} (其中 | 是管道操作符)
链式管道 {{ 输入数据 | date | uppercase }}
管道流通方向自左向右,逐层执行,使用脚手架命令 ng g p pipes/test
<!-- 管道 -->
<p>{{dateStr}}</p>
<p>{{ dateStr | date:'yyyy-MM-dd HH:mm:ss'}}</p>
<p>{{ name | uppercase}}</p>
<p>{{ name | lowercase}}</p>
<p>{{ name | test}}</p>
import { TestPipe } from '../pipes/test.pipe';
dateStr:Date = new Date()
name:string = 'Tina'
test.pipe.ts
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'test',
standalone: true
})
export class TestPipe implements PipeTransform {
transform(value: unknown, ...args: unknown[]): unknown {
return '>>>' + value + '<<<';
}
}
14.组件生命周期以及属性传递
Angular会按照一下顺序执行钩子方法。你可以用它来执行以下类型的操作。
ngOnChanges() 当angular设置或重新设置数据绑定的输入属性时响应
ngOnInit() 在angular第一次显示数据绑定和设置指令/组件的输入属性之后,初始化指令/组件
ngDoCheck() 检测,并在发烧Angular无法或不愿意自己检测的变化时作出反应
ngAfterContentInit() 当Angular把外部内容投影进组件视图或指令内容之后调用
ngAfterContentChecked() 每当Angular检查完被投影到组件或指令中的内容之后调用
ngAfterViewInit() 当Angular初始化完组件视图及其子视图或包含该指令的视图之后调用
ngAfterViewChecked() 每当Angular做完组件视图和子视图或包含该指令的视图的变量检测之后调用
ngOnDestory() 每当Angular每次销毁指令/组件之前调用并清扫。在这儿反订阅可观察对象和分离事件处理
组件属性传值
<app-title [title] = "title"></app-title>
import { Component, Input } from '@angular/core';
@Input()
title?:string
15.组件交互
- @Input
父组件通过 @Input 给子组件绑定属性设置输入类数据 - @Output
父组件给子组件传递一个事件,子组件通过@Output弹射触发事件
<!-- 父 home.component.html -->
<app-title [title] = "title" (addList) = addListFun($event)></app-title>
// home.component.ts
list:Array<string> =['Angular','vue']
addListFun(str:string){
this.list?.push(str)
}
<!-- 子 title.component.html -->
<button (click)="addBtnFun()">我要学react</button>
// title.component.ts
import { Component, EventEmitter, Input, Output } from '@angular/core';
@Output() addList = new EventEmitter()
addBtnFun(){
this.addList.emit('react')
}
- @ViewChild
通过 ViewChild 获取子组件实例,获取子组件数据
<!-- 父 home.component.html -->
<app-title #titleDom [title] = "title" (addList) = addListFun($event)></app-title>
<button (click)="addFun()">调用子组件</button>
// home.component.ts
@ViewChild('titleDom') child: any
addFun(){
this.child.addBtnFun()
}
16.Angular服务的讲解
使用 ng g s xxx 创建一个服务,通过@Injectable()装饰器标识服务。
import { Injectable } from '@angular/core';
@Injectable({
//root 表示注入到app.module.ts内, null 表示不设定区域, 还可以是某个模块的名字(一般就是懒加载模式)
//作用域设定
providedIn: 'root'
})
export class ListService {
constructor() { }
}
17.依赖注入
//list.service.ts
import { Injectable } from '@angular/core';
@Injectable({
//root 表示注入到app.module.ts内, null 表示不设定区域, 还可以是某个模块的名字(一般就是懒加载模式)
//作用域设定
providedIn: 'root'
})
export class ListService {
constructor() { }
list:Array<string> = ['Angular','React','Vue']
getList(){
return this.list
}
addList(str:string){
this.list.push(str)
}
}
如果想在home组件中注入数据,需要引入
<p *ngFor="let item of list">{{item}}</p>
<button (click)="addNodeFun()">我还想学node</button>
import { ListService } from '../serves/list.service';
export class HomeComponent {
constructor(private listService:ListService){}
list:Array<string> | undefined
ngOnInit():void{
console.log(this.listService)
this.list = this.listService.getList()
console.log(this.list)
}
addNodeFun(){
this.listService.addList('Node')
}
}
18.路由基础以及路由配置
<a [routerLink]="['/home']" routerLinkActive="router-link-active">首页</a>
<a [routerLink]="['/hello']" routerLinkActive="router-link-active">hello</a>
<!-- 路由组件渲染的位置 -->
<router-outlet />
//app.routes.ts
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { HelloComponent } from './hello/hello.component';
export const routes: Routes = [
{
path:'home',
component:HomeComponent
},
{
path:'hello',
component:HelloComponent
}
];
//app.components.ts
import { Component } from '@angular/core';
import { RouterLink, RouterOutlet } from '@angular/router';
import { HelloComponent } from './hello/hello.component'
import { HomeComponent } from './home/home.component';
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet,RouterLink],
templateUrl: './app.component.html',
styleUrl: './app.component.less',
})
export class AppComponent {
}
19.通配路由配置以及路由执行机制讲解
{
path:'', //默认路由
component:HomeComponent
},
//通配
{
path:'**',
component:HelloComponent
}
20.路由嵌套
{
path:'home',
component:HomeComponent,
children:[
{
path:'list',
component:ListComponent
}
]
},
home.component.html
<a [routerLink]="['/home/list']" routerLinkActive="router-link-active" >LIST</a>
<!-- home路由下的子路由渲染的位置 -->
<router-outlet></router-outlet>
21.路由传参
1.query
在a标签上添加一个参数queryParams,并通过this.routerinfo.snapshot.queryParams获取参数
<a [routerLink]="['/hello']" [queryParams]="{id:3,name:'Tina'}" routerLinkActive="router-link-active">hello</a>
<p>路由传参query</p>
<p>{{id}}----{{name}}</p>
import { ActivatedRoute } from '@angular/router';
export class HelloComponent {
constructor(private routerinfo:ActivatedRoute){}
ngOnInit(){
this.id=this.routerinfo.snapshot.queryParams['id']
this.name=this.routerinfo.snapshot.queryParams['name']
}
}
2.params
修改路由配置文件path,路由导航a标签routerlink后面数组的第二个参数为传递的值
并且通过subscribe请阅的方式获取name参数
{
path:'hello/:name/:id',
component:HelloComponent
}
<a [routerLink]="['/hello','我是url传递参数',2]" routerLinkActive="router-link-active">hello</a>
import { ActivatedRoute } from '@angular/router';
export class HelloComponent {
constructor(private routerinfo:ActivatedRoute){}
ngOnInit(){
this.routerinfo.params.subscribe((params:Params) => {
this.name = params['name']
this.id= params['id']
})
}
}