本文主要讲解ANgular在Windows平台的环境搭建。
安装Node.JS
官网下载稳定版本的node.js:https://nodejs.org/en/
安装对话框一路默认下一步,当然,可以按需修改安装路径。
安装完成后会自动将Node.JS的根目录添加到环境变量,读者可以自行查询。
在nodejs根目录,创建node_global,node_cache文件夹
以管理人员身份运行CMD。输入如下命令:
1 2 3 4 npm config set prefix "D:\DevelopmentToolRoot\WebFront\nodejs\node_global" npm config set cache "D:\DevelopmentToolRoot\WebFront\nodejs\node_cache"
将node_global、node_cache所在路径添加到path环境变量中
全局安装最常用的 express 模块
配置淘宝镜像并安装cpm :
1 2 3 4 5 6 npm config set registry https://registry.npmmirror.com npm install -g cnpm
可以使用配置查看命令,查看配置是否成功:
安装Angular
首先卸载已经安装的版本:
1 2 3 4 5 6 7 8 9 npm uninstall -g angular-cli npm uninstall --save-dev angular-cli npm uninstall -g @angular/cli npm cache verify
开始安装,报权限不允许的错误就使用管理员的方式打开cmd!
1 2 cnpm install -g @angular/cli@latest
检查是否安装成功
项目创建
1 2 3 4 5 6 7 8 9 10 11 ng new projectName ng new projectName --skip-install cd projectNamecnpm install
项目编译&启动
在浏览器键入:http://localhost:4200/,可看到欢迎页面
常见报错:
angular 6中使用socket.io报错:global is not define 在src/polyfills.ts中添加
1 (window as any ).global = window ;
创建一个组件 在项目根目录下使用如下命令:
1 2 3 4 5 6 D:\root\WorkSpace\AngularRoot\Start>ng g component component/news CREATE src/app/component/news/news.component.html (19 bytes) CREATE src/app/component/news/news.component.spec.ts (614 bytes) CREATE src/app/component/news/news.component.ts (262 bytes) CREATE src/app/component/news/news.component.scss (0 bytes) UPDATE src/app/app.module.ts (398 bytes)
vscode终端执行ng serve报错:
1 2 3 4 5 ng : 无法加载文件 C:\Users\root\AppData\Roaming\npm\ng.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID=135170 中的 about_Execution_Policie s。 所在位置 行:1 字符: 1 + ng serve + ~~
在搜索框搜索:Windows PowerShell ISE,执行如下命令并选A(全是)即可解决
1 set-ExecutionPolicy RemoteSigned
angular不建议使用dom操作来改变class
在src/app/app.module.ts文件夹中添加:
1 2 3 4 5 6 7 8 9 10 import { FormsModule } from '@angular/forms' ;@NgModule ({ imports : [ FormsModule ], })
html 如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <div > <form class ="form" [formGroup ]="infoForm" > <ng-container > <div formArrayName ="infos" > <div *ngFor ="let info of infos.controls; let i = index" > <ng-container [formGroupName ]="i" > <label > {{ info.get("name").value}}</label > <input type ="text" formControlName ="value" [id ]="i" > </ng-container > </div > </div > <button (click )="onSubmit()" > 保存 </button > </ng-container > </form > </div >
ts代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 export class FormComponent implements OnInit { constructor (private fb :FormBuilder ) { } infoForm = this .fb .group ({ infos : this .fb .array ([]), }); get infos (): FormArray { return this .infoForm .get ('infos' ) as FormArray ; } ngOnInit ( ) { const fm = this .fb .group ({ id : 1 , name : "aaa" , value : "aiaiai" , }); this .infos .push (fm); const fm1 = this .fb .group ({ id :2 , name :"bbb" , value :"bibibi" , }); this .infos .push (fm1); const fm2 = this .fb .group ({ id :3 , name :"ccc" , value :"cicici" , }); this .infos .push (fm2); var playerInterval_dvp = setInterval (() => { console .log ("aaa" ) }); } onSubmit ( ){ console .log (this .infos .at (1 ).get ('name' ).value ); console .log ((this .infos .at (1 ))) console .log ((this .infos .at (1 ).value )) console .log ((this .infos .at (1 ).value as MyInfoInterface )) console .log ((this .infos .at (1 ).value as MyInfoInterface ).value ) } } export interface MyInfoInterface { id : number ; name : string ; value : string ; }
点击按钮后,结果如下:
创建一个服务 1 ng g service service/storage
在src/app/app.module.ts文件夹中添加:
1 2 3 4 5 6 7 import { StorageService } from './service/storage.service' ;@NgModule ({ providers : [StorageService ], })
在组件文件中添加:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import { StorageService } from '../../service/storage.service' ;export class SearchComponent implements OnInit { public keyword :string ="电脑" ; public history :any []=[]; storage :StorageService ; constructor (storage :StorageService ) { this .storage = storage; var hi = this .storage .get ("history" ); if (hi) { this .history = hi; } } ngOnInit ( ) { } }
DOM操作 DOM操作最好在ngAfterViewInit函数中进行,ngOnInit中操作的话,可能一些dom还没有加载完成导致获取不到DOM
在angular中,操作dom的方式有两种:使用原生js和使用ViewChild
1 <p #myfirstdom > domopt works!</p >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import { Component , OnInit , ViewChild } from '@angular/core' ;@Component ({ selector : 'app-domopt' , templateUrl : './domopt.component.html' , styleUrls : ['./domopt.component.scss' ] }) export class DomoptComponent implements OnInit { @ViewChild ("myfirstdom" , {static :true }) myfirstdom :any ; constructor ( ) { } ngOnInit ( ) { } ngAfterViewInit ( ){ console .log (this .myfirstdom ); this .myfirstdom .nativeElement .innerHTML = "aaa" ; } }
父子组件传值 方式一: 数据、函数、父组件本身都能通过该方法传递。
父组件中定义:
1 2 3 4 5 6 7 8 9 10 export class NewsComponent implements OnInit { public title :string = "新闻" ; @ViewChild ("myheader" , {static :true }) header :any ; constructor ( ) { } ngOnInit ( ) { } }
1 <app-header #myheader [title ]="title" > </app-header >
子组件中定义:
1 2 3 4 5 6 7 8 9 10 11 import { Component , OnInit , Input } from '@angular/core' ;export class HeaderComponent implements OnInit { @Input () title :any ; constructor ( ) { } ngOnInit ( ) { } }
方式二: 子组件通过事件驱动的方式给父组件发消息。
子组件配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import { Component , OnInit , Input , Output , EventEmitter } from '@angular/core' ;export class HeaderComponent implements OnInit { @Output () outer = new EventEmitter (); constructor ( ) { console .log (this .dt ) } ngOnInit ( ) { this .mvvm ="初始值" } sendParent ( ){ console .log ("header的sendParent方法" ); this .outer .emit ("header的sendParent" ); } }
父组件配置:
1 <app-header (outer )="run($event)" > </app-header >
1 2 3 4 5 6 7 8 9 10 11 import { Component , OnInit , ViewChild } from '@angular/core' ;export class NewsComponent implements OnInit { constructor ( ) { } ngOnInit ( ) { } run (arg :any ){ alert ("新闻中的run方法,还可以直接把整个新闻组件传给header!!!" + arg); } }
异步处理 有两种:rxjs(observable)或者promise,主要介绍一下rxjs
使用rxjs: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import {map,filter} from 'rxjs/operators' import { RequestService } from '../../service/request.service' export class HomeComponent implements OnInit { request :RequestService ; constructor (request :RequestService ) { } ngOnInit ( ) { var streamNum = this .request .getRxjsIntervalTimer (); streamNum.pipe ( filter ( (value )=> { if (Number (value)%2 == 0 ) { return true ; } return false ; }), map ( (val )=> { return Number (val)*Number (val); }) ).subscribe ((value ) => { console .log (value); }); } }
RequestServer:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import { Observable } from 'rxjs' ;export class RequestService { constructor ( ) { } getRxjsIntervalTimer ( ){ var cnt = 0 ; return new Observable ( (observe )=> { setInterval (()=> { cnt++; observe.next (cnt); }, 1000 ); } ); } }
使用get、post请求 app.module.ts:
1 2 3 4 5 6 7 8 9 10 import { HttpClientModule } from '@angular/common/http' @NgModule ({ imports : [ HttpClientModule , ] })
http如下:
1 2 3 4 5 6 7 <button (click )="getRequest()" > get请求</button > <button (click )="postRequest()" > post请求</button > <button (click )="getJsonpData()" > jsonp请求</button >
请求逻辑如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import { HttpClient , HttpHeaders } from '@angular/common/http' export class RequesthttpComponent implements OnInit { http :HttpClient ; constructor (http :HttpClient ) { this .http = http; } ngOnInit ( ) { } getRequest ( ){ this .http .get ("http://a.itying.com/api/productlist" ).subscribe ((value )=> { console .log (value); }); } postRequest ( ) { var httpOptions = { headers : new HttpHeaders ({"Content-Type" : "application/json" }) }; this .http .post ("www.baidu.com" , {"username" :"zhangsan" , "password" :"123" }, httpOptions).subscribe ((data )=> { console .log (data); }); } getJsonpData ( ){ this .http .jsonp ("http://a.itying.com/api/productlist" , "callback" ).subscribe ((value )=> { console .log (value); }); } }
路由 在app-routing.module.ts可配置静态路由:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import { NewsComponent } from './components/news/news.component' ;import { MovieComponent } from './components/movie/movie.component' ;import { GameComponent } from './components/game/game.component' ;import { ContentComponent } from './components/content/content.component' ;const routes : Routes = [ { path :"news" , component : NewsComponent , },{ path :"movie" , component : MovieComponent , },{ path :"game" , component : GameComponent , },{ path :"content" , component : ContentComponent , },{ path :"**" , component : NewsComponent , }, ];
加routerLinkActive可实现激活
1 2 3 <a [routerLink ]="'/news'" routerLinkActive ="active" > 新闻</a > <a [routerLink ]="'/movie'" routerLinkActive ="active" > 电影</a > <a [routerLink ]="'/game'" routerLinkActive ="active" > 游戏</a >
组件路由并传参:
get路由:
1 2 3 4 { path :"content" , component : ContentComponent , }
父:
1 2 3 4 5 6 7 8 <p > news works!</p > <ul > <li *ngFor ="let item of list; let i=index;" > <a [routerLink ]="'/content'" [queryParams ]="{aid:i}" > {{i}} === {{item}}</a > </li > </ul >
子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import { ActivatedRoute } from '@angular/router' ;export class ContentComponent implements OnInit { router :ActivatedRoute ; constructor (router :ActivatedRoute ) { this .router = router; } ngOnInit ( ) { this .router .queryParams .subscribe ((value )=> { console .log (value); }); } }
动态路由:
1 2 3 4 { path :"content/:aid" , component : ContentComponent , }
父:
1 2 3 4 5 <ul > <li *ngFor ="let item of list; let i=index;" > <a [routerLink ]="['/content/', i]" > {{i}} === {{item}}</a > </li > </ul >
子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import { ActivatedRoute } from '@angular/router' ;export class ContentComponent implements OnInit { router :ActivatedRoute ; constructor (router :ActivatedRoute ) { this .router = router; } ngOnInit ( ) { this .router .params .subscribe ((value )=> { console .log (value); }); } }
js 动态路由:
app-routing.module.ts:
1 2 3 4 { path :"content/:aid" , component : ContentComponent , }
父
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { Router } from '@angular/router' ;export class NewsComponent implements OnInit { router :Router ; constructor (router :Router ) { this .router = router; } ngOnInit ( ) { this .router .navigate (["/content" , "123" ]); } }
子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import { ActivatedRoute } from '@angular/router' ;export class ContentComponent implements OnInit { router :ActivatedRoute ; constructor (router :ActivatedRoute ) { this .router = router; } ngOnInit ( ) { this .router .params .subscribe ((value )=> { console .log (value); }); } }
js get路由:
1 2 3 4 { path :"content" , component : ContentComponent , }
父:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import { Router , NavigationExtras } from '@angular/router' ;export class NewsComponent implements OnInit { router :Router ; constructor (router :Router ) { this .router = router; } ngOnInit ( ) { let params :NavigationExtras = { queryParams :{aid :"123" }, fragment :"anchor" } this .router .navigate (["/content" ], params); } }
子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import { ActivatedRoute , Router } from '@angular/router' ;export class ContentComponent implements OnInit { router :ActivatedRoute ; constructor (router :ActivatedRoute ) { this .router = router; } ngOnInit ( ) { this .router .queryParams .subscribe ((value )=> { console .log (value); }); } }
路由嵌套:
根:
1 2 3 4 <a [routerLink ]="'/news'" routerLinkActive ="active" > 新闻</a > <a [routerLink ]="'/movie'" routerLinkActive ="active" > 电影</a > <a [routerLink ]="'/game'" routerLinkActive ="active" > 游戏</a > <router-outlet > </router-outlet >
app-routing.module.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 import { NgModule } from '@angular/core' ;import { Routes , RouterModule } from '@angular/router' ;import { NewsComponent } from './components/news/news.component' ;import { MovieComponent } from './components/movie/movie.component' ;import { GameComponent } from './components/game/game.component' ;import { ContentComponent } from './components/content/content.component' ;import { SystemsetComponent } from './components/movie/systemset/systemset.component' ;import { SystemmaintainComponent } from './components/movie/systemmaintain/systemmaintain.component' ;import { GamesetComponent } from './components/game/gameset/gameset.component' ;import { GameupdateComponent } from './components/game/gameupdate/gameupdate.component' ;const routes : Routes = [ { path :"news" , component : NewsComponent },{ path :"movie" , component : MovieComponent , children :[ { path :"systemset" , component :SystemsetComponent , },{ path :"systemmaintain" , component :SystemmaintainComponent , },{ path :"**" , component :SystemsetComponent , } ], },{ path :"game" , component : GameComponent , children :[ { path :"gameset" , component :GamesetComponent , },{ path :"gameupdate" , component :GameupdateComponent , },{ path :"**" , component :GamesetComponent , } ], },{ path :"content" , component : ContentComponent , },{ path :"**" , component : NewsComponent , }, ]; @NgModule ({ imports : [RouterModule .forRoot (routes)], exports : [RouterModule ] }) export class AppRoutingModule { }
component/movie/movie.component.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <p > movie works!</p > <div class ="content" > <div class ="left" > <a [routerLink ]="'/movie/systemset'" routerLinkActive ="active" > 系统设置</a > <br > <br > <a [routerLink ]="'/movie/systemmaintain'" routerLinkActive ="active" > 系统维护</a > </div > <div class ="right" > <router-outlet > </router-outlet > </div > </div >
component/game/game.component.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <p > game works!</p > <div class ="content" > <div class ="left" > <a [routerLink ]="'/game/gameset'" routerLinkActive ="active" > 游戏设置</a > <br > <br > <a [routerLink ]="'/game/gameupdate'" routerLinkActive ="active" > 游戏更新</a > </div > <div class ="right" > <router-outlet > </router-outlet > </div > </div >
Subject和Observable的区别 Observable是Subject的特例,Subject是典型的发布订阅模式,可以将消息传递给多个订阅者,但是Observable只能一对一。
关于Renderer2的介绍 Renderer2 是 Angular 提供的一个用于操作 DOM 的服务类。它允许你在不直接访问浏览器的 DOM API 的情况下,通过抽象层安全地操作 DOM。Renderer2 是为了增强跨平台兼容性和更好的安全性而设计的,使得你的应用可以在浏览器、服务器端渲染(如 Angular Universal)以及 Web Workers 等不同的环境中运行。
关于dom操作 constructor( private Re2: Renderer2, private el: ElementRef, // 其他依赖项… ) { }
直接访问宿主元素:
ElementRef 提供了对 Angular 组件、指令或 HTML 元素的宿主元素的直接引用。通过 el.nativeElement,你可以访问并操作该元素。例如,如果这个 ElementRef 是在一个组件中注入的,那么 el.nativeElement 指向该组件的根 DOM 元素。 与 Renderer2 结合使用:
在你提供的构造函数中,ElementRef 通常与 Renderer2 一起使用。Renderer2 提供了一组安全的方法来操作 DOM,而 ElementRef 提供了操作的目标元素。 例如,在 ngOnInit 或其他方法中,你可能会通过 el.nativeElement 获取 DOM 元素,然后使用 Renderer2 对其应用样式、添加类或处理事件。
Data URL 例如,一个图像的Data URL可能看起来像这样:
1 data:image/png;base64 ,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==
在这个例子中:
image/png 指定了MIME类型,表示这是一个PNG图像。
base64 表示数据是使用Base64编码的。
后面的长字符串是图像数据的Base64编码表示。
它允许将小文件直接嵌入到网页或网络请求中,而不需要从服务器上单独请求资源。Data URL 通常用于图像、字体、CSS、JavaScript 和其他小型文件,以减少HTTP请求的数量,从而提高页面加载速度。
本章完结