路由
常用指令
npm i --save 包名:软件依赖
npm i --save-dev 包名:开发依赖
ng new 项目名:新建Angular项目
ng new 项目名 --skip-install --style=scss:跳过依赖的安装
ng build -prod:生产环境编译
ng serve:启动开发服务器
npm install -g json-server:根据json生成rest API
json-server 文件位置:使用json-server
基本配置和使用
const routes: Routes = [
// 基本配置
{ path: "index", component: IndexComponent },
// 子路由
{ path: "user", component: UserComponent, children: [
{ path: "info", component: InfoComponent },
{ path: 'settings', component: SettingsComponent }
]},
// 重定向
{ path: "", redirectTo: '/index', pathMatch: 'full' },
// 通配符,其他路由失败的,会跳转到这个视图
{ path: '**', component: EmptyComponent }
];
路由跳转
// 1.利routerLink在html中直接跳转
<a [routerLink]="['/']">跳转到主页</a>
<a [routerLink]="['./settings']">跳转到设置页</a>
// 2.在ts文件中用Router进行跳转
<button (click)="skipToUser()" >跳转到用户页面</button>
constructor(private route: Router) { }
skipToUser() {
this.route.navigateByUrl("user")
}
路由数据传递
在查询参数中传递数据
<a [routerLink]="['/user']" [queryParams]="{id:1}">跳转到用户页</a>
constructor(private route: ActivatedRoute) { }
ngOnInit() {
console.log(this.route.snapshot.queryParams["id"]);
}
在路由路径中传递数据
<a [routerLink]="['/user', 1]">跳转到用户页</a>
// 路由配置
{ path: "user/:id", component: UserComponent }
constructor(private route: ActivatedRoute) { }
ngOnInit() {
console.log(this.route.snapshot.params["id"]);
}
在路由配置中传递数据
<a [routerLink]="['/user']">跳转到用户页</a>
{ path: "user", component: UserComponent, data:[{id:2}] }
ngOnInit() {
console.log(this.route.snapshot.data[0]["id"]);
}
ts文件中跳转传递数据
// A页面点击button跳转到B页面, 并在路径还参数中分别传递数据
// 1.A页面配置
<button (click)="skipToUser()">跳转到用户页</button>
constructor(private route: Router) { }
skipToUser() {
this.route.navigate(['/user', 5], { queryParams: { id: 10 }});
}
// 2.路由配置
{ path: "user/:id", component: UserComponent }
// 3.B页面配置
constructor(private route: ActivatedRoute) { }
ngOnInit() {
// console.log(this.route.snapshot.params["id"]);
// console.log(this.route.snapshot.queryParams["id"]);
this.route.params.subscribe((params: Params) => {
console.log(params["id"])
})
}
辅助路由(多页面公用聊天窗口)
// 1.html中代码
<router-outlet name="aux"></router-outlet>
{ path:'chat', component:ChatComponent, outlet:'aux' },
<a [routerLink]="[{outlets:{aux:'chat'}}]">开始聊天</a>
// 不显示
<a [routerLink]="[{outlets:{aux:null}}]">结束聊天</a>
// 同时跳转到home页面
<a [routerLink]="[{outlets:{primary:home, aux:'chat'}}]">开始聊天</a>
路由守卫
钩子函数
CanActivate: 处理导航到某路由的情况
CanDeactivate: 处理从当前路由离开的情况
Resolve: 在路由激活之前获取路由数据
当用户已经登录并拥有某些权限时才可以进入某些路由
1.实现CanActivate接口,返回boolean类型参数
export class Guard implements CanActivate {
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean>|Promise<boolean>|boolean {
return undefined;
}
}
2.配置路由参数
{ path: "index", component: IndexComponent, canActivate: [Guard] }
3.注入对象
@NgModule({
providers: [Guard]
})
当用户未执行保存操作视图离开当前页,给用户提醒
实现CanDeactivate接口,注意泛型参数的传入,其他同上
export class UnsaveGuard implements CanDeactivate<IndexComponent> {
canDeactivate(component: IndexComponent) {
return window.confirm("还没有保存,确定要离开吗");
}
}
当进入一个页面前,提前请求号数据,携带参数进入页面
1.实现Resolve接口,注意泛型的传入
export class UserResolve implements Resolve<User> {
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<User>|Promise<User>|User {
return new User('123', '张三');
}
2.定义model类
export class User {
constructor(public id: string, public name: string) {}
}
3.路由配置和注入对象同上
4.数据接收
constructor(private route: ActivatedRoute) { }
public userId: string;
public userName: string;
ngOnInit() {
this.route.data.subscribe((data: [User]) => {
this.userId = data[0].id;
this.userName = data[0].name;
})
}
依赖注入
基本用法
1.创建服务
ng g service product/product
2.编写服务
getProduct(): Product {
return new Product('123', 'productName')
}
getProduct(): Product {
return new Product('123', 'productName')
}
3.添加配置
@NgModule({
providers: [ProductService]
})
4.使用
private productId: string;
private productName: string;
constructor(private productService: ProductService) {
}
ngOnInit() {
this.productId = this.productService.getProduct().id;
this.productName = this.productService.getProduct().name;
}
基于原有服务提供的服务
1.创建服务
2.编写服务
export class AnotherProductService implements ProductService{
getProduct(): Product {
return new Product("aaaaa", "another-product");
}
}
3.在component中添加配置
@Component({
providers: [{provide: ProductService, useClass: AnotherProductService}]
})
4.使用
private productId: string;
private productName: string;
constructor(private productService: AnotherProductService) {
ngOnInit() {
this.productId = this.productService.getProduct().id;
this.productName = this.productService.getProduct().name;
}
工厂函数提供器
providers: [{
provide: ProductService,
useeFactory: (logger: LoggerService, appConfig) => {
if (appConfig.isDev) {
return new ProductService(logger);
} else {
return new AnotherProductComponent(logger);
}
},
deps: [LoggerService, "APP_CONFIG"]
}, LoggerService,
{
provide: "APP_CONFIG", useValue: {isDev: false}
}]
数据绑定
事件绑定
<input (input)="onInputEvent($event)">
<button (click)="saved = true">
属性绑定
<img [src]="imgUrl">
<img src="{{imgUrl}}">
<tr><td [attr.colspan]="size">html属性绑定</td></tr>
// 完全替换class中的内容
<div class="aaa bbb" [class]="someExpression">something</div>
// 值为true时,绑定special样式
<div [class.special]="isSpecial">something</div>
// 同时控制多个css类是否显示
<div [ngClass]="{aaa:isA, bbb:isB}">
// 样式绑定
<button [style.color]="isSpecial ? 'red' : 'green'">Red</button>
<div [ngStyle]="{'font-size':this.canSave?'italic':'normal'}">
双向绑定
<input [(ngModel)]="name">
管道
1.创建管道
ng g pipe pipe
2.编写规则
export class PipePipe implements PipeTransform {
transform(value: any, args?: any): any {
return value == 1 ? "合格" : "不合格";
}
}
3.使用
<p>{{ num | pipe}}</p>
组见间通信
父组件向子组件传值
父组件
<app-son [fatherName]="'fatherName'">
子组件
@Input()
public fatherName: string;
子组件向父组件传值
子组件
@Output('sonEmit')
emitter: EventEmitter<string> = new EventEmitter();
emitData() {
this.emitter.emit("子组件中的数据");
}
父组件
<app-son (sonEmit)="receiveData($event)"></app-son>
receiveData(data: string) {
console.log(data);
}
用服务作为中间人传递数据
生命周期钩子
生命周期函数
红色只会调用一次,绿色会调用多次。
constructor:构造器函数,一般用于注入服务
ngOnChanges:检测到输入数据变化,首次触发发生在ngOnInit前。注意对象的属性发生变化时监听不到 (监测对象地址 )
ngOnInit:组件初始化,通常会设置一些初始值
ngDoCheck:变更监测时触发,input框的点击也会触发。
ngAfterContentInit:被投影的内容初始化完毕时调用(先父后子)
ngAfterContentChecked:被投影的内容变更监测完毕时调用
ngAfterViewInit:子组件初始化之后 ,不能做数据更新的操作(先子后父)
ngAfterViewChecked:子组件发生变化检测之后,不能做数据更新的操作
ngOnDestroy:组件注销时的清理工作,通常用于移除事件监听,退订可观察对象等
变更监测
投影(父组件中的布局显示在子组件中)
1.定义父组件的内容
<app-son>
<div class="header">这是父组件中的头部</div>
<div class="footer">这是父组件中的尾部</div>
</app-son>
2.定义子组件的投影点
<ng-content select=".header"></ng-content>
<ng-content select=".footer"></ng-content>
http请求(代理配置和使用)
1.根目录下创建proxy.config.json文件,写入代码
{
"/api": {
"target": "http://www.classcool.net",
"secure": false,
"changeOrigin":true,
"pathRewrite": {
"^/api": ""
}
}
}
2.更改启动配置文件:package.json,在scripts的start里面加入代理配置
"scripts": {
"start": "ng serve --proxy-config proxy.config.json"
}
3.app.module.ts中引入HttpclientModule
@NgModule({
imports: [
HttpClientModule
]
})
4.使用
dataSource: Observable<any>;
products: any;
constructor(private http: HttpClient) {
this.products = this.http.get<any>('/api/user/info').subscribe(data => console.log(data));
console.log(this.dataSource);
}
模块只初始化一次的方式
import { NgModule, SkipSelf, Optional } from '@angular/core';
export class CoreModule {
constructor(@Optional() @SkipSelf() parent: CoreModule) {
if (parent) {
throw new Error('模块已经存在,不能再次加载!')
}
}
}