快速上手angular8常见使用(二)

上一篇文章地址:快速上手angular8常见使用(一)

1、HttpClient

HttpClient服务:是Angular提供的用于发起异步XHR请求的对象
使用步骤:
1)主模块中导入

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from "@angular/common/http";

// 装饰器中的元数据来实现
@NgModule({
  // 导入
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule
  ],
  // 依赖注入提供程序的列表。
  providers: [],
  // 自动引导的组件列表。
  bootstrap: [AppComponent]
})
export class AppModule { }

2)在组件中声明依赖于HttpClient服务对象,就会被自动注入进来

import { HttpClient } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-ng-client',
  templateUrl: './ng-client.component.html',
  styleUrls: ['./ng-client.component.scss']
})
export class NgClientComponent implements OnInit {

  constructor(private http:HttpClient) { }

  ngOnInit() {
  }

}

3)调用HttpClient实例实现异步请求

export class NgClientComponent implements OnInit {
    private productList: object[] = []
    // 依赖注入服务对象
    constructor(private http: HttpClient) { }

    ngOnInit() {
    }
    public loadMore(): void {
        const url: string = 'http://localhost:3000/news'
        const options: object = {
            headers: new HttpHeaders({
                'Content-Type': 'application/json'
            })
        };
        this.http.get(url, options).subscribe((res) => { })
    }

}

2、组件的生命周期钩子

当你的应用通过调用构造函数来实例化一个组件或指令时,Angular 就会调用那个在该实例生命周期的适当位置实现了的那些钩子方法。

Angular 会按以下顺序执行钩子方法。可以用它来执行以下类型的操作。

export class NgClientComponent implements OnInit, OnChanges {
  private productList: object[] = []
  // 依赖注入服务对象
  constructor(private http: HttpClient) {
    console.log('constructor 组件对象被创建')
  }
  ngOnChanges() {
    // 如果组件绑定过输入属性,那么在 ngOnInit() 之前以及所绑定的一个或多个输入属性的值发生变化时都会调用。
    console.log('ngOnChanges 属性的值发生变化时都会调用')
  }
  ngOnInit() {
    // 在 Angular 第一次显示数据绑定和设置指令/组件的输入属性之后,初始化指令/组件。
    // 常用
    console.log('ngOnInit 组件初始化完毕——Vue.js的mounted')
  }
  ngDoCheck() {
    // 检测,并在发生 Angular 无法或不愿意自己检测的变化时作出反应。
    console.log('ngDoCheck 组件检查到了系统对自己影响')
  }
  ngAfterContentInit() {
    // 当 Angular 把外部内容投影进组件视图或指令所在的视图之后调用。第一次 ngDoCheck() 之后调用,只调用一次。
    console.log('ngAfterContentInit 组件的内容初始化完成')
  }
  ngAfterContentChecked() {
    // ngAfterContentInit() 和每次 ngDoCheck() 之后调用。
    console.log('ngAfterContentChecked 组件的内容发生变化时需要检查')
  }
  ngAfterViewInit() {
    // 第一次 ngAfterContentChecked() 之后调用,只调用一次。
    console.log('ngAfterViewInit 组件的视图初始化完成')
  }
  ngAfterViewChecked() {
    // ngAfterViewInit() 和每次 ngAfterContentChecked() 之后调用。
    console.log('ngAfterViewChecked 组件的视图发生变化需要检查')
  }
  ngOnDestroy() {
    // 在 Angular 销毁指令或组件之前立即调用。
    // 常用
    console.log('ngOnDestroy 组件即将从DOM树上卸载,适合执行一些资源释放性语句')
  }
}

在这里插入图片描述

3、父子组件传值

方向1:父=>子
父组件通过“子组件自定义属性”向下传递数据给子组件
在这里插入图片描述

  // 一个装饰器对应一个属性
  @Input()
  private child2Name = null

方向2:子=>父
子组件通过触发特额定的事件(其中携带着数据),把数据传递给父组件(父组件提供事件处理方法)
在这里插入图片描述
方向3:兄弟之间传递
子=>父=子
父子组件传递数据的简便方法:父亲直接使用子组件的应用
一定程度上违反了“最少知识法则”

总结:组件模板中可以出现的内容:

<div>
	<myc01 />
	<button (click)="doUpdateName()">修改</button>  
	<p *ngIf="isMarried"></p>
	<ul>
	   <li *ngFor="let i of emList"></li>
	 </ul>
	 <div #myDiv></div>
</div>

① HTML 标准元素/属性
②组件对象的元素
③angular指令
④模型数据/方法——Model
⑤事件对象/子组件传递的数据——$event
⑥模板变量——在模板中声明变量时,如ngFor循环等
⑦子元素识别符号——都是以开头,在脚本中使用ViewChild进行关联

4、路由和导航

多页面用应:一个项目中有个多个完整的HTML文件,使用超链接跳转,销毁一颗DOM树,同步请求另一颗,得到之后城建新的DOM树;不足:DOM树要反复重建,间隔中客户端一片空白
单页面用应:称为SPA(Single Page Application),整个项目中有且只有一个“完整的”HTML文件,其他的“页面”都只是HTML的片段;需要哪个“页面”就将其异步请求下来,“插入”到“完整的”HTML文件中
优势:整个项目中客户端只需要下载一个HTML页面,创建一个完整的DOM树,页面跳转都是一个DIV替换另一个DIV而已——能够实现过场动画
不足: 不利于SEO访问优化

在这里插入图片描述

1、Angular中使用“单页应用”的步骤:
①定义“路由词典”——[{URL-组件},{URL-组件}]
app-routing.module.ts

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ChildAComponentComponent } from './child-acomponent/child-acomponent.component';
import { IndexComponent } from './index/index.component';
import { LoginComponent } from './login/login.component';
import { Myc01ParentBlogComponent } from './myc01-parent-blog/myc01-parent-blog.component';
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';
import { RegisterComponent } from './register/register.component';
import { UserInforComponent } from './user-infor/user-infor.component';


const routes: Routes = [
  {
    path: '',
    component: IndexComponent,
    children: [
      {
        path: 'child-a', // child route path
        component: ChildAComponentComponent, // child route component that the router renders
      },
      {
        path: 'center',
        component: Myc01ParentBlogComponent
      },
      {
        path: 'user/:id',
        component: UserInforComponent
      }
    ]
  }, {
    path: 'login',
    component: LoginComponent
  }, {
    path: 'register',
    component: RegisterComponent
  },
  // 重定向
  {
    path: '',
    redirectTo: '',
    pathMatch: 'full'  // 路由匹配方式 完全匹配
  },
  // ** 地址匹配任意格式的地址
  {
    // 添加 404 页面
    path: '**',
    component: PageNotFoundComponent
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

②注册“路由词典”
app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http'

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { Myc01ParentBlogComponent } from './myc01-parent-blog/myc01-parent-blog.component';
import { Myc02Child1ModifyComponent } from './myc02-child1-modify/myc02-child1-modify.component';
import { Myc02Child2PhotoComponent } from './myc02-child2-photo/myc02-child2-photo.component';
import { UserCenterComponent } from './user-center/user-center.component';
import { LoginComponent } from './login/login.component';
import { RegisterComponent } from './register/register.component';
import { IndexComponent } from './index/index.component';

// 声明路由词典——路由地址和路由组件的对应集合

@NgModule({
  declarations: [
    AppComponent,
    Myc01ParentBlogComponent,
    Myc02Child1ModifyComponent,
    Myc02Child2PhotoComponent,
    UserCenterComponent,
    LoginComponent,
    RegisterComponent,
    IndexComponent,
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

③创建路由组件挂载点——称为“路由出口”

<router-outlet></router-outlet>

④访问测试

在这里插入图片描述
在这里插入图片描述

2、路由跳转/导航:从一个路由地址跳转到另一个
实现方案:
方式1:

<any routerLink="/index" ></any>

注意:①可用于任意标签②跳转地址应该以/开头,防止以相对当方式跳转
方式2:

<button (click)="goLogin()">用户信息</button>

index.modules.ts

import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, ParamMap } from '@angular/router';

@Component({
  selector: 'app-index',
  templateUrl: './index.component.html',
  styleUrls: ['./index.component.scss']
})
export class IndexComponent implements OnInit {

  constructor(private route: ActivatedRoute, private router: Router) { }

  ngOnInit() {
  }
 goLogin() {
    // 跳转到详情
    this.router.navigate(['/user', 2]);
    // this.router.navigateByUrl('/user/' + 2)
  }
}

注意:Route类是RouterModule提供的一个服务类,声明以来即可使用
3、获取路由参数

 ngOnInit() {
    // 组件初始化完成,读取路由参数进而根据路由参数进行处理

    this.route.params.subscribe((data) => {
      this.userId = data.id
    })
  }

4、路由嵌套

const routes: Routes = [
  {
    path: '',
    component: IndexComponent,
    children: [
      {
        path: 'child-a', // child route path
        component: ChildAComponentComponent, // child route component that the router renders
      },
      {
        path: 'center',
        component: Myc01ParentBlogComponent
      },
      {
        path: 'user/:id',
        component: UserInforComponent
      }
    ]
  }, {
    path: 'login',
    component: LoginComponent
  }, {
    path: 'register',
    component: RegisterComponent
  },
  // 重定向
  {
    path: '',
    redirectTo: '',
    pathMatch: 'full'  // 路由匹配方式 完全匹配
  },
  // ** 地址匹配任意格式的地址
  {
    // 添加 404 页面
    path: '**',
    component: PageNotFoundComponent
  }
];

5、路由守卫
在这里插入图片描述

路由守卫的步骤:
①创建路由守卫 class
简化 ng g guard 守卫名字

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

②在路由词典中使用路由守卫

 {
    path: '',
    component: IndexComponent,
    canActivate: [LoginGuard],
  }, 

模拟工作中登录案例
①·ng g s auth· 创建用户权限serve

import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  // 登陆状态
  isLoggedIn = false;
  // 保存登录后重定向的路径
  redirectUrl: string;
  constructor() { }
  // 模拟登录
  login(): Observable<boolean> {
    this.isLoggedIn = true
    return of(true)
  }

  logout(): void {
    this.isLoggedIn = false;
  }

}

ng g guard login 登录路由守卫

import { Injectable } from "@angular/core";
import { CanActivate, Router, UrlTree, } from "@angular/router";
import { AuthService } from "./auth.service";


// 路由守卫都是“可注入的”服务对象
@Injectable({
  providedIn: 'root'
})
export class LoginGuard implements CanActivate {
  private isLogin = false
  constructor(private router: Router, private authServe: AuthService) {

  }
  canActivate() {
    return this.checkLogin()
  }
  private checkLogin(): true | UrlTree {
    // 已经登录,直接返回true
    if (this.authServe.isLoggedIn) return true;
    return this.router.parseUrl('/login')
  }
}

ng g component login 登录组件

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '../auth.service';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
  public userName: string = ''
  public password: string = ''
  public message: string = ''
  constructor(public authService: AuthService, public router: Router) { }

  ngOnInit() {
  }
  doSubmit() {
    if (this.userName === '123' && this.password === '123') {
      this.authService.isLoggedIn = true
      this.authService.login().subscribe(() => {
          // 跳转回重定向路径
          this.router.navigateByUrl('/')
      })
    }


  }

}

<p [class.text-danger]="!authService.isLoggedIn">{{message}}</p>
<input type="text" [(ngModel)]="userName" />
<br>
<input type="password" [(ngModel)]="password" />
<br>
<button (click)="doSubmit()">登录</button>

④ 路由词典配置

const routes: Routes = [
  {
    path: '',
    component: IndexComponent,
    canActivate: [LoginGuard],
    children: [
      {
        path: 'child-a', // child route path
        component: ChildAComponentComponent, // child route component that the router renders
      },
      {
        path: 'center',
        component: Myc01ParentBlogComponent
      },
      {
        path: 'user/:id',
        component: UserInforComponent
      }
    ]
  }, {
    path: 'login',
    component: LoginComponent,
  }, {
    path: 'register',
    component: RegisterComponent
  },
  // 重定向
  {
    path: '',
    redirectTo: '',
    pathMatch: 'full'  // 路由匹配方式 完全匹配
  },
  // ** 地址匹配任意格式的地址
  {
    // 添加 404 页面
    path: '**',
    component: PageNotFoundComponent
  }
];
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嘴巴嘟嘟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值