视频来源【建议1.5px倍速】Angular教程_Angular8 Angular9 Angular12入门实战视频教程-2023年更新【IT营】
Angular 初识 Angular 环境配置 npm install -g @angular/cli
cnpm install -g @angular/cli
备注:npm
若安装慢,可尝试使用cnpm
方式代替,需要先安装cnpm
依赖
npm install -g cnpm --registry=https://registry.npm.taobao.org
Angular 创建项目 直接安装
跳过依赖安装
ng new angularDemo --skip-install
项目创建完成后安装依赖并启动
npm install / cnpm install
Augular 开发工具推荐 工具:Vscode
工具插件:Angular Language Service
Angular 结构目录
*.spec.ts
属于测试文件,开发过程不需要关注Angular 组件使用 命令行创建组件 使用命令创建组件,会自动引入并配置到app.module.ts
中
ng g component components/news
components/news
属于指定的目录/文件
补充 ng generate component dashboard --module=app.module
备注:需要指定--module=app.module
,否则报错
Error: More than one module matches. Use skip-import option to skip importing the component into the closest module. More than one module matches. Use skip-import option to skip importing the component into the closest module.
组件使用方法 组件news.components.ts
,其中selector
为组件使用名称
import { Component } from '@angular/core'; @Component({ selector: 'app-news', templateUrl: './news.component.html', styleUrls: ['./news.component.css'] }) export class NewsComponent { }
在app.component.html
中使用方式
<!-- 新组件使用 --> <app-news></app-news> <!-- 原app.component.html内容--> <div> this is angular Index ! </div>
组件里面绑定数据 组件.ts
定义一个属性title
规范定义属性格式
public student: string = "XXXX"; public test: any = 'XXXXX';
import { Component } from '@angular/core'; @Component({ selector: 'app-news', templateUrl: './news.component.html', styleUrls: ['./news.component.css'] }) export class NewsComponent { title = "我是一个新闻组件~"; }
在news.component.html
使用属性
页面预览显示
基本数据类型 参考博客
Boolean 布尔 number 数字 string 字符串 array 数组 any 任意类型 tuple 元组类型 enum 枚举 null和undefined void类型 never类型 布尔
let flg : boolean = true;
数字
字符串
Typescript支持使用单引号或双引号来表示字符串类型。支持使用模板字符串反引号(`)来定义多行文本和内嵌表达式。使用${expr}的形式嵌入变量或表达式。
let name : string = "Angular"; let year : number = 2; let words : string = `你好${name}${year}`;
数组
let arr : number[] = [1,2]; let arr : Array<number> = [1,2];
元组
元组类型用来表示已知元素数量和类型的数组,各元素类型不必相同。
let xx : [string, number]; xx = ['Angular', 2];
枚举
enum Name {LI,WANG,ZHAO}; let nm : Name = Name.WANG; alert(nm);//1 枚举默认下标是从0开始,可以手动修改。 enum Name2 {LI=3,WANG,ZHAO=8}; let nm2 : Name2 = Name2.WANG; alert(nm2);//4 alert(Name2.ZHAO);//8
null和undefined
let x : number | null | undefined;
void类型
function hello() :void {alert("hello");}
never类型
never是其他类型的子类型,代表不会出现的值。声明为never类型的变量只能被never类型所赋值,在函数通常表现为抛出异常或无法执行到终止但(例如无限循环)
let x : never; x = (() => {throw new Error('exeption occur')})();
在组件里面绑定属性 属性title
的动态取值,需要用[]
中括号包起来。
<div [title]="student"> this is angular Index ! </div>
在组件里面绑定html代码片段 htmlH:any = "<h1>我是html代码段!</h1>";
<span [innerHTML]="htmlH"></span>
引入图片 #静态文件资源目录`assets`下 <img src="assets/images/all.png" /> #图片资源目录由动态获取 <img [src]="pic"/>
Angular 组件方法/命令 在组件里面使用循环 *ngFor="let item of arr
标准语法格式,arr
为定义的数据对象
<ul> <li *ngFor="let item of arr"> {{item}} </li> </ul>
循环数据显示数组的索引(key) public list:any[] = [ { "title":"我是标题01" }, { "title":"我是标题02" }, { "title":"我是标题03" }, ];
<ul> <li *ngFor="let item of list;let key = index;"> {{key}} -- {{item.title}} </li> </ul>
ngif的使用 public flag:boolean = false;
<div *ngIf="flag"> {{flag}} </div> <div *ngIf="!flag"> {{flag}} </div>
ngif搭配ngfor使用 方式01 [ngif]实现
<ul> <li *ngFor="let item of list;let key = index;"> <span *ngIf="key == 2" class="red"> {{key}} -- {{item.title}} </span> <span *ngIf="key != 2"> {{key}} -- {{item.title}} </span> </li> </ul>
方式02 [ngclass]实现
<ul> <li *ngFor="let item of list;let key = index;"> <span [ngClass]="{'red': key==1,'blue':key==0}"> {{key}} -- {{item.title}} </span> </li> </ul>
ngswitch的使用 public orderStatus:number = 1;
<span [ngSwitch]="orderStatus"> <p *ngSwitchCase="1"> 订单已支付 </p> <p *ngSwitchCase="2"> 订单已支付并确认 </p> <p *ngSwitchDefault> 订单未支付 </p> </span>
ngclass的使用 <div> <span [ngClass]="{'red': flag,'blue': !flag}"> ngclass属性 </span> </div>
ngstyle的使用 静态方式写法
<p [ngStyle]="{'color':'red'}">我是一个p标签</p>
动态方式写法
主要arr
,如果是动态取值,不加'
单引号。静态方式写法需要加单引号。
public arr:string = 'red';
<p [ngStyle]="{'color':arr}">我是一个p标签</p>
管道 public today:any = new Date();
<P>{{today}}</P> <p>{{today | date: 'yyyy-MM-dd HH:mm:ss'}}</p>
执行方法 <hr> <button (click)="run()">run</button> <hr> <input type="text" (keydown)="keyDown($event)">
run(){ alert('执行自定义方法!'); } keyDown(event: any){ if( event.code == 'Enter' ){ console.log('敲了一下回车'); }else{ console.log(event.code); } }
双向绑定 mvvm 需要在app.module.ts
中引入FormsModule
import { FormsModule } from '@angular/forms';
并且在imports
中声明当前FormModule
的使用
@NgModule({ declarations: [ AppComponent, NewsComponent, HomeComponent ], imports: [ BrowserModule, FormsModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
public keywords:string = '';
<input type="text" [(ngModel)]="keywords"> {{keywords}}
Angular 服务引入 ng g service services/my_new_service
app.module.ts
中声明服务import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import {TestService} from './services/test.service'; @NgModule({ declarations: [ ... ], imports: [ ... ], providers: [TestService], bootstrap: [...] }) export class AppModule { }
在需要使用的component
也需要在声明一次
import { TestService } from 'src/app/services/test.service';
官方推荐使用service
的方式
通过构造方法注入参数对象
constructor(public test:TestService){ let t = this.test; console.log(t.get()); }
Angular 操作原生dom节点 方式一 <div id="box"> this is a box ! </div> <br> <div id="box1" *ngIf="flag"> this is a box1 ! </div>
// 组件和指令初始化完成,不是dom加载完成 ngOnInit(): void { let oBox:any = document.getElementById('box'); console.log(oBox.innerHTML); oBox.style.color = 'red'; // let oBox1:any = document.getElementById('box1'); // console.log(oBox1.innerHTML); // oBox1.style.color = 'red'; } //视图加载完成后触发的方法,dom加载完成 (建议把dom操作放这里) ngAfterViewInit(): void { let oBox1:any = document.getElementById('box1'); console.log(oBox1.innerHTML); oBox1.style.color = 'red'; }
方式二 引入
import { ViewChild } from '@angular/core';
声明
<div #box2> 我是一个dom节点 </div>
赋值
//获取dom节点并赋值box2 @ViewChild('box2') box2:any;
使用
ngAfterViewInit(): void { console.log(this.box2.nativeElement); this.box2.nativeElement.style.width= 200; this.box2.nativeElement.style.height= 200; this.box2.nativeElement.style.background= 'red'; }
Angular 组件间的传值 父->子组件间的传值 1.这里示例是父组件->子组件传值
2,若需要父组件使用子组件,则@ViewChild
是一种方法
传值 父组件定义传值参数
public title:string = '父组件传值';
父组件页面html引入子组件
title 是父组件传值参数
<app-son [title]="title"></app-son>
子组件引入Input
模块
import { Input } from '@angular/core';
子组件接收值
传方法 父组件定义方法
run(){ alert('父组件的方法!'); }
父组件页面html引入子组件
‘run’不需要加(),表示的是方法,而不是执行方法
<app-son [run]='run'></app-son>
子组件调用
@Input() run:any; runParentsMethod(){ this.run(); }
传递组件 父组件页面html引入子组件
‘this’表示的是整个组件
<app-son [home]='this'></app-son>
子组件调用
@Input() home:any; runParentsMethod(){ <!-- this.run(); --> //获取父组件的值 alert(this.home.msg); //调用父组件方法 this.home.run(); }
子组件通过@output触发父组件方法 比较复杂,用的比较少,但是要知道。
子组件引入output和EventEmitter
import { Output,EventEmitter } from '@angular/core';
子组件中实例化EventEmitter
@Output() private outer = new EventEmitter<string>();
子组件通过EventEmitter对象outer实例广播数据
sendParent(){ this.outer.emit('msg from child'); }
父组件调用子组件时候,定义接收事件,outer就是子组件EventEmitter对象outer
<app-header (outer)="runParent($event)"> </app-header>
父组件接收到数据会调用自己的runParent方法,这个时候就可以拿到子组件数据
runParent(e){ //e 就是子组件传值给父组件的参数 console.log(e); }
拓展:非父子组件通信 localstage 服务形式(service公有的组件) Angular 异步数据编程 TestService
服务调用异步方法
//同步方法 get(){ return 'this is a test service !'; } //异步方法 //1.回调函数处理异步方法数据 getCallBackData(cb:any){ setTimeout(() => { var name = '张三'; cb(name); }, 1000); } //2. promise处理异步方法数据 getPromiseData(){ return new Promise((resolve,reject)=>{ //resolve(); 成功执行函数 //reject(); 失败执行函数 setTimeout(() => { var name = '张三--promise'; resolve(name); }, 1000); }); } //3. rxjs 处理异步方法数据 getrxjsData(){ return new Observable(observe=>{ //成功数据返回 // observe.next(); //失败数据返回 // observe.error(); setTimeout(() => { var name = '张三--rxjs'; observe.next(name); }, 1000); }); }
获取异步方法返回参数结果
ngOnInit(): void { //同步方法 this.msg = this.testService.get(); console.log(this.msg); //异步方法 this.testService.getCallBackData((data:any)=>{ console.log(data); }); //Promise var promiseData = this.testService.getPromiseData(); promiseData.then((data)=>{ console.log(data); }); //rxjs var rxjsData = this.testService.getrxjsData(); rxjsData.subscribe((data)=>{ console.log(data); }); }
rxjs
取消订阅
var rxjsData = this.testService.getrxjsData(); let d = rxjsData.subscribe((data)=>{ console.log(data); }); setTimeout(() => { d.unsubscribe(); //取消订阅 }, 1000);
rxjs
多次执行异步方法
Promise方法不能多次执行(没有这个能力)
//4. rxjs 多次执行处理异步方法数据 getrxjsIntervalData(){ return new Observable(observe=>{ //成功数据返回 // observe.next //失败数据返回 // observe.error let count = 0 ; setInterval(() => { count ++ ; var name = '张三--rxjs-interval-'+count; observe.next(name); }, 3000); }); }
rxjs
的工具函数map\filter
import {map,filter} from 'rxjs/operators';
let number = this.testService.getRxjxIntervalNumData(); number.pipe( //过滤工具 filter((value:any)=>{ if(value%2==0){ return true; }else{ return false; } }) //多个工具组合使用,用','号隔开 , //map工具 map((value:any)=>{ return value * value ; }) ).subscribe((data)=>{ console.log(data); });
Angular 数据交互 国外测试接口网站
get请求数据 在app.module.ts
中引入HttpClientModule
并注入
import {HttpClientModule} from '@angular/common/http'
@NgModule({ declarations: [ ... ], imports: [ HttpClientModule ], providers: [...], bootstrap: [...] }) export class AppModule { }
在需要使用组件中,引入
并在构造方法中声明对象
import {HttpClient} from '@angular/common/http';
constructor( public http: HttpClient ){ }
get
方法调用
get(){ console.log('get方法调用~'); let api = "https://reqres.in/api/users?page=2"; this.http.get(api).subscribe((response)=>{ console.log(response); }); }
post 提交数据 在需要使用组件中,引入
并在构造方法中声明对象
post
需要设置请求头,需要HttpHeaders
模块
import {HttpClient,HttpHeaders} from '@angular/common/http';
post(){ console.log('post方法调用~'); const httpOptions = { headers: new HttpHeaders({'Content-Type':'application/json'}) }; let api = "https://reqres.in/api/users"; this.http.post(api,'{"name": "morpheus","job": "leader"}',httpOptions).subscribe((response:any)=>{ console.log(response); }); }
JsonP 跨域的一种解决方案
import {HttpClientModule,HttpClientJsonpModule} from '@angular/common/http';
@NgModule({ declarations: [ ... ], imports: [ HttpClientModule, HttpClientJsonpModule ], providers: [...], bootstrap: [...] }) export class AppModule { }
JsonP需要服务器后端支持
验证是否支持方法:
url?callback=xxx 或 url?cb=xxx
可响应接口参数返回是否有xxx
标识名称(xxx是自己定义的一个参数,非必须按xxx标识参数使用)
jsonP(){ console.log('jsonP~'); //jsonP请求,服务器必须支持jsonP this.http.jsonp('url','callback').subscribe((response)=>{ console.log(response); }); }
使用第三方工具axios
请求 axios
安装模块
引入模块
import axios from 'axios';
封装service服务供组件调用
import { Injectable } from '@angular/core'; import axios from 'axios'; @Injectable({ providedIn: 'root' }) export class HttpServiceService { constructor() { } axiosGet(api:string){ return new Promise((reslove,rject)=>{ axios.get(api) .then(function (response) { // console.log(response); reslove(response); }) }) } }
组件中使用
import { Component } from '@angular/core'; import {HttpClient,HttpHeaders} from '@angular/common/http'; import { HttpServiceService } from 'src/app/services/http-service.service'; @Component({ selector: 'app-demo04', templateUrl: './demo04.component.html', styleUrls: ['./demo04.component.css'] }) export class Demo04Component { constructor( public http: HttpClient ,public httpservice: HttpServiceService ){ } axios(){ console.log('axios方法调用~'); let api = "https://reqres.in/api/users?page=2"; this.httpservice.axiosGet(api).then((data)=>{ console.log(data); }); } }
Angular 路由 创建新项目时候,需要确认路由创建。
路由文件名app-routing.module.ts
创建的组件需要挂载到路由中
import { NewsComponent } from './components/news/news.component'; import { HomeComponent } from './components/home/home.component'; import { ProductComponent } from './components/product/product.component'; const routes: Routes = [ {path:'home',component:HomeComponent}, {path:'news',component:NewsComponent}, {path:'product',component:ProductComponent} ];
匹配不到路由,默认跳转到指定页面
{path:'**',redirectTo:'home'},
导航选中激活
active
对应样式名
<a routerLink='/product' routerLinkActive="active" >product</a>
get 传值 <a [routerLink]="[ '/newscontent' ]" [queryParams]="{'aid':key}">{{item}}</a>
子组件接收传参
import { ActivatedRoute } from '@angular/router';
import { Component } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; @Component({ selector: 'app-newscontent', templateUrl: './newscontent.component.html', styleUrls: ['./newscontent.component.css'] }) export class NewscontentComponent { constructor(public route:ActivatedRoute){ } ngOnInit(): void { this.route.queryParams.subscribe((data)=>{ console.log(data); }); } }
动态路由传值 :aid
是动态路由传值需要获取的参数名称
{path:'newscontent/:aid',component:NewscontentComponent},
传值
<ul><li *ngFor="let item of list;let key = index"> <!-- get传值 --> <!-- <a [routerLink]="[ '/newscontent' ]" [queryParams]="{'aid':key}">{{item}}</a> --> <!-- 动态路由传值 --> <a [routerLink]="[ '/newscontent/',key ]" >{{item}}</a> </li></ul>
接收
ngOnInit(): void { this.route.params.subscribe((data:any)=>{ console.log(data); }); }
动态路由的js
跳转 import { Router } from '@angular/router';
js
跳转
goJs(){ console.log('js路由跳转~'); this.router.navigate(['/newscontent/','123']); }
get传值跳转路由 【Angular教程_Angular8 Angular9 Angular12入门实战视频教程-2023年更新【IT营】】- P14 - 21:36进度处
父子嵌套路由 父子嵌套路由修改
const routes: Routes = [ {path:'home',component:HomeComponent,children:[ {path:'menu01',component:Menu01Component}, {path:'menu02',component:Menu02Component}, ]} ];
父页面添加路由组件
<div> <div class="left"> <a [routerLink]="[ '/home/menu01' ]">菜单01</a> <a [routerLink]="[ '/home/menu02' ]">菜单02</a> </div> <div class="right"> <router-outlet></router-outlet> </div> </div>
Ionic Angular + Ionic 可以开发app
目前暂无学习规划,待Angular
知识吸收归纳后跟进。