Angular学习

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每次销毁指令/组件之前调用并清扫。在这儿反订阅可观察对象和分离事件处理


image.png

组件属性传值

<app-title [title] = "title"></app-title>
import { Component, Input } from '@angular/core';

  @Input()
  title?:string

15.组件交互

  1. @Input
    父组件通过 @Input 给子组件绑定属性设置输入类数据
  2. @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')
  }
  1. @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> &nbsp;&nbsp;&nbsp;&nbsp;
<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']
            })
     }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容

  • Angular7入门总结篇 一、Angular 介绍 根据项目数统计 angular(1.x 、2.x 、4.x、...
    痞_4fc8阅读 363评论 0 3
  • 声明 本系列文章内容梳理自以下来源: Angular 官方中文版教程 官方的教程,其实已经很详细且易懂,这里再次梳...
    请叫我大苏阅读 1,079评论 0 6
  • angular 中文官网 环境搭建 快速创建 ng generate component 组件名 简写 ng ...
    zlb123456阅读 400评论 0 0
  • 路由是导航的另一个名字。路由器就是从一个视图导航到另一个视图的机制。 1.导航,那么我们专门做一个导航组件。这个组...
    价值投机168阅读 2,099评论 0 2
  • 介绍 Angular 可以帮助你为 Web、移动端或桌面构建现代应用程序。包含http等功能是框架,vue只能称为...
    pisfans阅读 114评论 0 0