Angular入门笔记一

这篇博客介绍了Angular的基础知识,包括如何安装、创建和运行Angular项目。详细讲解了组件的创建、生命周期钩子,数据绑定的各种方式如插值表达式、属性绑定、事件绑定和双向数据绑定。还涉及了管道、依赖注入、路由和导航、表单绑定以及组件间的通信。适合初学者入门Angular。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基础

官网连接(中文):
https://angular.cn/start

简介:angular是由Google维护的一款开源javaScript。Anguar1.5叫做angularJs,Angular4.0称为Angular,Angular1.5到Angular4.0是完全重写。(我们要学的是Angular)

安装、创建及运行:

要求node大于10.9,查看node版本:
node -v

安装angular命令:npm install -g @angular/cli

查看安装的版本命令:ng version

image.png

创建项目命令:ng new my-angular

运行项目:ng serve 或者npm start

运行的端口是:http://localhost:4200/

组件component:

创建组件的方法:可以手动新建文件、命令快捷键组件。
其中命令快创建组件的:ng g component 组件名
例如在components目录下创建一个test01的组件:ng g component /components/test01

//test01.component.ts文件内容
// 装饰器 Decorator 用于指定class的用途
// 创建组件class,还得去注册组件class
import { Component } from "@angular/core";

@Component({
  // selector: "[test01]",  //属性<div test01="xxx"/>
  // selector: ".test01",   //class使用  <div class="test01">
  selector: 'test01',   //组件使用 <test01/>
  template: '<h1>我自己定义的组件</h1>'
})
export class test01 {
  title = "我是自己定义的组件"
}

app.module.ts文件里进行组件的注册:

import { Mycomponent01 } from './mycomponent01';   //引入

在这里插入图片描述
然后就可以来到app.component.html使用这个组件了:

<test01></test01>

生命周期:

在这里插入图片描述

ngOnchanges:

如果组件绑定过输入属性,那么在 ngOnInit() 之前以及所绑定的一个或多个输入属性的值发生变化时都会调用。
注意,如果你的组件没有输入属性,或者你使用它时没有提供任何输入属性,那么框架就不会调用 ngOnChanges()

ngOnInit:

其实每次routerLink都会执行。(从其他页面跳过来)在 Angular 第一次显示数据绑定和设置指令/组件的输入属性之后,初始化指令/组件。
在第一轮 ngOnChanges() 完成之后调用,**只调用一次**。
而且即使没有调用过 ngOnChanges(),也仍然会调用 ngOnInit()(比如当模板中没有绑定任何输入属性时)。
ngOnInit() 是组件获取初始数据的好地方,相当于mounted。

ngDoCheck:

检测,并在发生 Angular 无法或不愿意自己检测的变化时作出反应。
紧跟在每次执行变更检测时的 ngOnChanges() 和 首次执行变更检测时的 ngOnInit() 后调用。

ngAfterContentInit:

当 Angular 把外部内容投影进组件视图或指令所在的视图之后调用。
ngDoCheck() 之后调用,**只调用一次**。

ngAfterContentChecked:

每当 Angular 检查完被投影到组件或指令中的内容之后调用。
ngAfterContentInit() 和每次 ngDoCheck() 之后调用.
例如:
<mycom01><p>{{name}}</p></mycom01>

ngAfterViewInit:

当 Angular 初始化完组件视图及其子视图或包含该指令的视图之后调用。
ngAfterContentChecked() 之后调用,**只调用一次。**

ngAfterViewChecked:

每当 Angular 做完组件视图和子视图或包含该指令的视图的变更检测之后调用。
ngAfterViewInit() 和每次 ngAfterContentChecked() 之后调用。
例如:
Template:’<p>{{name}}</p>”

ngOnDestroy:

每当 Angular 每次销毁指令/组件之前调用并清扫。
把清理逻辑放进 ngOnDestroy() 中,这个逻辑就必然会在 Angular 销毁该指令之前运行。
这里是释放资源的地方,这些资源不会自动被垃圾回收。如果你不这样做,就存在内存泄漏的风险。
取消订阅可观察对象和 DOM 事件。
停止 interval 计时器。
反注册该指令在全局或应用服务中注册过的所有回调。
ngOnDestroy() 方法也可以用来通知应用程序的其它部分,该组件即将消失。

数据的绑定:

插值表达式:

可以:
{{age+2}}
{{age>20?true:false}}
逻辑运运算符: || &&
{{ageArr.length}}
{{anme.toUpperCase()}}
不可以:
{{new Date()}}
{{JSON.pase(name)}}

属性绑定:

<p title=”{{name}}”></p>    //就像小程序一样
<p [title] = “name” ></p>   //或者这样
<p [title]=”’哈哈哈:’+name”>
图片的绑定:
(相对路径:不推荐)
<Img [src]=”’../../assets/img/’+imglist[1].src”>

事件绑定:

<button (click)="handleFn()">   //记住**事件一定要加上括号**
change、blur、keydown、keyup、mouseenter、mousedown、mouseup、dbclick、drag、copy、keyup.enter等
带参数的函数可以,例如:
html文件:
<input type="search" placeholder="请输入要搜索的数据" (keyup.enter)="handleFocus($event)" />
ts文件:
handleFocus(e:any){
	console.log(e.target.value)
}

指令绑定:

循环*ngfor:
<!-- html文件 -->
<!-- 例如 
	testLists = ["html","css","js","ts","nodejs","angular"] 
-->
<ol>
	<li *ngfor="let item of testLists;index as i;">
	<span>下标:{{i}}---值:{{item}}</span>
	<span>第一条数据:{{first}}---最后一条数据{{last}}</span>	
	<span>还有even:boolean偶数就为true、odd:boolean奇数就为true</span>
	</li>
</ol>

在这里插入图片描述

*ngif:

if判断:

<!-- if -->
<div *ngif="age>=18">你成年了</div>
<!--if else -->
<div *ngif="age>=18;else testChild">你成年了</div>
<ng-template #testChild>你还是小屁孩</ng-template>

if与for不可以一起使用,所以推荐方法container与div一起使用:

<!-- 
	lists = ["wumiao","五秒","加油"]
-->
<ng-container *ngFor="let item of lists;let i = index">
  <div *ngIf="i%2==0">
    {{item}}-{{i}}
  </div>
</ng-container>
ngSwitch:
<!-- switch -->
<!-- 例如:
	public a:number = 2  
-->
<!-- ---分割线-- -->
<ul [ngSwitch]="a">
  <li *ngSwitchCase="1">我是1</li>
  <li *ngSwitchCase="2">我是2</li>   <!-- 只显示了他 -->
  <li *ngSwitchCase="3">我是3</li>
  <li *ngSwitchDefault>我是默认的</li>    <!-- 没有显示 -->
</ul>
样式绑定ngStyle:

绑定的样式必须是个对象。

<!-- 例如 -->
<p [ngStyle]="testStyleObj">我的颜色</p>
<!-- ------分割线----  -->
<!--  
	testStyleObj = { color:'#db1000',backgroundColor:'#383','border-color':'#252'} 
-->

当然单个样式的话可以:

<p [style.color]="'#db1000'" [style.border]="'1px solid #db1000'">一窜字符串</p>
<p [style.font-size.px]="fontSize">一窜字符串</p>
<!-- 分割线 -->
<!-- 
	fontSize = 16 
-->
动态绑定ngClass:
<!-- 绑定一个class  -->
<button [ngClass]="className">提交</button>
<!-- 分割线 -->
<!--  
	className = {
		btn:true
	}
-->
<!-- 绑定多个class -->
<button [ngClass]="className2">提交</button>
<!-- 分割线 -->
<!-- 
	className2 = {
		btn:true,
		'btn-success':true,
		'btn-danger':false
	}
-->

或者:

<button type="button" class="btn" [class.btn-success]="isTrue==true">提交</button>
<!-- 分割线 -->
<!-- 
	isTrue:boolean = false
-->

双向数据绑定ngModel:

需要注意:
使用ngModel需要导入FormsModel模块:

//来到app.module.ts文件
import {FormsModel} from "@angular/forms"
@ngModule({
	import:[
		BrowserModule,
		FormsModel   //导入才能使用ngModel,
	]
})

然后简单使用:

<input type="test" [(ngModel)]="userName" value=""/>
<!-- 分割线 -->
<!-- 
	public userName:string = ""
-->

管道Pipe:

预定管道:

angular有10几个预定管道,就是angular自己提供的,可以直接拿来使用。
  1. List item
  2. LowerCase:全部小写
  3. UpperCase:全部大写
  4. TitleCase:首字母大写
  5. Slice:切片 //slice: start[:end]
  6. Json:将转为json字符串,解决了JSON的undefault
  7. Number:将字符串转为数字 //number:‘4.1-4’ 整数4位,小数1到4位
  8. Currency:金额(货币格式)
  9. date:时间管道
    例如:
<ol>
	<li>WuMiao 全部小写后为:{{'WuMiao'|LowerCase}}</li>
	<li>WuMiao 全部大写后为:{{'WuMiao'|UpperCase}}</li>
	<li>wumiao 切片下标2到最后:{{'wumiao'|Slice:2}}</li>
	<li>12345.98765 整数位4位,小数位2位后:{{12345.98765|Number:'4.2'}}</li>
	<li>1652843665414 将时间戳转为指定格式:{{'1652843665414'|date:'yyyy-MM-dd HH:mm:ss'}}</li>
</ol>

自定义管道:

创建管道的命令:ng g pipe 管道名
例如:在文件夹pipes里新建一个名为sex管道:ng g pipe /pipes/sex

<!-- 来到SexPipe管道文件 -->
import {Pipe} from “angular/core”;
@Pipe({
	Name:sex
}export class SexPipe{
	transform(val){   //管道的函数代码只能在transform里面  //转换、变形
		if(val==1){
			return}else if(val == 2){
			return}else{
			return 保密
		}	
	}
}

来到html使用;

<p>我的性别为:{{userSex | sex}}</p>
<!-- 分割线 -->
<!-- 
	public sex:number = 2
-->
当然指定一管道也可以有默认参数:
export class sexPipe{
	transform(sex,age="18"){ // xxxx}
}
使用的话就:(给默认值参数传参使用冒号)
<p>{{userSex | sex:'19'}}</p>

依赖注入service:

将组件与服务分开、可以服用、将数据访问的智者交给服务,
而数据就从充当着数据访问、逻辑吃力的功能,
而服务存在的目的就是对各个component之间的交互提供了一个途径。
感觉跟vue里的vuex有点相似。

创建服务service的命令:ng个service 服务文件名
例如:在文件夹services里新建一个inputForm服务:ng g service inputForm
input-form.service.ts文件:

import { Injectable } from '@angular/core';
@Injectable({
  providedIn: 'root'
})
export class InputFormService {
  username:string = ""
  constructor() { }
  getName(): string{
    return this.username
  }
  setName(name: string): void{
    this.username = name
  }
}

然后来到app.module.ts全局引入:

import { InputFormService } from './services/input-form.service';
   declarations: [
   // ...
  ],
  imports: [
    BrowserModule,
    // ...
  ],
  providers: [InputFormService],
})

或者局部组件引入依赖:(来到要使用组件的ts文件)
在这里插入图片描述

使用就是:


import { Component, OnInit } from '@angular/core';
import { InputFormService } from 'src/app/services/input-form.service';
@Component({
  selector: 'app-c',
  templateUrl: './c.component.html',
  styleUrls: ['./c.component.less'],
  // providers:[InputFormService]  //局部依赖,如果是全局的话就不需要这一步
})
export class CComponent implements OnInit {
  constructor(private inputFormService:InputFormService) { }
  ngOnInit(): void {
  // 使用它service
    this.inputFormService.setName("wumiao")
    console.log(this.inputFormService.getName())  //打印 wumiao
  }
}

路由和导航

路由定义与跳转

路由是先到先得,所以静态的推荐放在前面的。404、通配符放在最后面的。
angular单页面医用效果

例如有新建两个组件:
ng g component /components/testa
ng g component /components/testb
然后来到app.modules.ts文件:

import { RouterModule } from '@angular/router';
import AppComponent from "../xxxxx省略"
import TestaComponent from "xxx省略"
// ....省略
//路由自定义,注意注册不可以以斜杠开头
let routes = [
  {path: "", pathMatch:"full",redirectTo:"index"},   //首页
  {path:"index",component:AppComponent },
  {path: "testa", component: TestaComponent,children:[
	{path:"testb/:id",component:testbComponet},	
   ]},
  {path:"**",component:ErrorComponet}   //404页面
]
imports: [
  BrowserModule,
  RouterModule.forRoot(routes)  //导入路由模块,并注册路由词典,用于根模块中。
],

来到html组件页面使用:
声明式:

<button routerLink="index?name='wumiao'">跳到index组件页面</button>
<a routerLink="/testa"> 跳到testa组件页面</a>
<p routerLink="testa">依旧跳到testa组件页面</p>
<div routerLink="testa/testb/12">跳到testb组件页面</div>
<!-- 路由的出口 -->
<router-outlet></router-outlet>

编程式:

<button (click)="handleTo()">点击进行组件跳转</button>
import { Router } from '@angular/router';
 constructor(private router: Router) { }
 	public id:number = 12
   	handleTo() {
		this.router.navigateByUrl("/index")
		//this.router.navigateByUrl('/testa?id=' + id)  //参数
		// this.router.navigate(['/testa/testb', id]);   //动态路由
	}
}

route获取当前路由的信息:

// 例如:来到testb.component.ts  
import { ActivatedRoute } from '@angular/router';
constructor(private route: ActivatedRoute) { }
	ngOnInit(): void {
		//activatedRoute获取当前路由信息
		//第一种:不用订阅的情况,获取初始值
		// Const params = this.route.snapshot.params
		// 第二种:推荐
   		 this.route.params.subscribe((data) => {   //可以去看看paramsMap
      	console.log(data)   //{id:12}
	})
}

路由守卫CanActivate:

新建路由守卫:ng 个guard 守卫文件名
例如新建一个登陆userLogin守卫:ng g guard userLogin
userLogin.guard.ts文件:

import { Injectable } from "@angular/core";
import { CanActivate, } from "@angular/router";

@Injectable({
  providedIn: "root"  //路由守卫都是“可注入的”服务对象
})
export class LoginCuard implements CanActivate {
  private isLogin = true;
  canActivate(): boolean {
    if (!this.isLogin) {
      return true  //可以激活后续的组件
    } else {
      return false   //不可以激活后续的组件
    }
  }
}

然后将守卫使用到路由上:
来到app.module.ts文件:

import { userLoginCuard } from './userLogin.guard';
//路由自定义,添加上守卫
let routes = [
  {path: "usercenter", component: UserCenterComponent, canActivate: [userLoginCuard] },
  { path: "**", component: Err01Component }
]

附加笔记:你们还可以了解Can’ActivateChild

Form表单:

注意要在app.modules.ts引入FormsModel

表单的数据绑定

可以简单的:

<form>
	<input [(ngModel)]="value" name="name"/>
	<input [(ngModel)]="value" [(ngModelOptions)="{name:'name'}"]/>
	<input [(ngModel)]="value" [ngModelOptions]="{standalone:true}"/>
</form>

使用formGroup:
例如:

<!-- 数据为:
	checkoutForm = {userName:'',userPasswd:''}
-->
<form [formGroup]="checkoutForm" (ngSubmit)="subfn(checkoutForm.value)">
  <label for="userName">用户名:</label>
  <input type="text" formControlName="userName" id="userName" />
  <hr>
  <label for="userPasswd">用户密码:</label>
  <input type="password" formControlName="userPasswd" id="userPasswd" />
  <button type="submit">提交</button>
</form>
<!-- ---分割线--- -->
<!--
	subfn(val){
		console.log(val)
	}
-->

FormBuilder与表单验证:

import { FormBuilder, Validators } from '@angular/forms';
  constructor(private formBuilder: FormBuilder) {
  }
  public rulesList = this.formBuilder.group({
    userName: ["",[Validators.required, Validators.minLength(2)]]  //必填,最小长度为2
  })

  get userName() {
    return this.rulesList.get("userName")
  }
  handleCls(val){
	console.log("提交了数据",val)
  }
<form [formGroup]="rulesList" (ngSubmit)="handleCls(rulesList.value)">
  <label for="userName">用户名:</label>
  <input type="text" id="userName" formControlName="userName" required>
  <!-- 下面这几行是username输入不满足验证要求提示的文字-->
  <div *ngIf="userName?.invalid && (userName?.dirty || userName?.touched)" class="alert alert-danger">
    <span *ngIf="pwd?.errors?.['required']">请填写User name</span>
    <span *ngIf="pwd?.errors?.['minlength']">userName应该至少2个字符</span>
 </div>
 <button type="submit">提交</button>
</form>

当然你也可以自定义表单验证:这个你们可以后续慢慢去了解。

import { FormBuilder, Validators, ValidatorFn, AbstractControl, ValidationErrors } from '@angular/forms';
constructor(private fromBuilder: FormBuilder) { }
  public formRules02 = this.fromBuilder.group({
    name: ["", [Validators.required, Validators.minLength(2), this.forbiddenNameValidator(/yqj/i, '不能以yqj开头')]]
  })
  handleCls(val: {}): void {
    this.formRules02.reset(0)
  }
  ngOnInit(): void {
  }
  get name() {
    return this.formRules02.get("name")
  }
  //自定义form验证
  forbiddenNameValidator(reg: RegExp, errorTips: string): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
      const forbidden = reg.test(control.value);
      return forbidden ? { forbiddenName: { value: errorTips } } : null;
    };
  }
<form [formGroup]="formRules02" (ngSubmit)="handleCls(formRules02.value)">
  <label for="name">用户名:</label>
  <input type="text" id="name" formControlName="name" required>
  <div *ngIf="name?.invalid && (name?.dirty || name?.touched)" class="alert alert-danger">
    <span *ngIf="name?.errors?.['required']">请填写last name</span>
    <span *ngIf="name?.errors?.['minlength']">last name应该至少4个字符</span>
    <span *ngIf="name?.errors?.['forbiddenName']">不能以yqj开头</span>
  </div>
  <button type="submit">提交</button>
</form>

组件之间的传值:

父传子@input:

父组件:father.component.html:

<h1>我只父组件<h1>
<hr>
<p>将父组件的fatherName传给子组件</p>
<app-son01 [fatherName]="faterName"></app-son01>

<!-- 分割线  -->
<!--
	public fatherName:string="father"
-->

子组件sonComponent.component.ts:

import { Component, Input, OnInit } from '@angular/core';
@Component({
  selector: 'app-son01',
  templateUrl: './son01.component.html',
  styleUrls: ['./son01.component.scss']
})
export class Son01Component implements OnInit {
  constructor() { }
  @Input() public fatherName: string = "";  //通过@input接受父组件通过组件穿过来的
  ngOnInit(): void {
  	console.log("我父组件的名字为"this.fatherName)
  }
}

子传父@output、@eventEmitter:

将子组件的传给父组件,借助事发射器eventEmitter.
son02.component.ts文件:

import { Component, EventEmitter, OnInit, Output } from '@angular/core';

@Component({
  selector: 'app-com02',
  templateUrl: './com02.component.html',
  styleUrls: ['./com02.component.scss']
})
export class Com02Component implements OnInit {
  constructor() { }
  public sonName: string = "";
  @Output() public cryEvent = new EventEmitter()
  uppar() {
    this.cryEvent.emit(this.sonName)
  }
  ngOnInit(): void {
  }
}

son02.component.html文件:

<p>son02 works!</p>
<input type="text" [(ngModel)]="sonName">
<button (click)="uppar()">提交</button>
<p>{{sonName}}</p>

父组件 father02.component.html文件:

<app-com02 (cryEvent)="doCry($event)"></app-com02>
<!--
  public doCry(e: any): void {
    this.username = e
  }
 -->

@ViewChild:

在这里插入图片描述
例如father03.component.html文件:

<app-son #son03></app-son>
<!-- <app-son #son03><app-son> -->
<!-- 分割线 -->
<!--
	@ViewChild('son03', { static: false }) child03!: any;   //有多个son03,就使用@viewChildren
	btn(){
		console.log(this.child03.sonName)   //打印子组件child03里的sonName
	}
-->

组件投影@ng-content

组件:

<p>a works!</p>
<ng-content select="[name='test01']"></ng-content>
<!-- 
	select="head" 表示选择第一个head标签
	select=".head" 表示选择第一个class="head"的标签
	select="#head" 表示选择第一个id="head"的标签
	select="[name=head]" 表示选择第一个name="head"的标签
	select="[slot=head]" 表示选择第一个slot="head"的标签 
-->

使用组件的地方:

<app-aa #aa>
  <h1 name="test01">hhhhhh</h1>
</app-aa>

第一阶段的简单笔记就到这里吧!end!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值