Angular進階學習之深入了解路由與表單

青灯夜游
發布: 2021-12-20 15:29:24
轉載
2224 人瀏覽過

本篇文章是Angular的進階學習,我們一起來詳細了解Angular中的路由和表單,希望對大家有幫助!

Angular進階學習之深入了解路由與表單

Angular的路由介紹

在單一頁面應用程式中,需要在定義好的不同檢視中(元件)來回切換,而不用去伺服器取得新頁面,要實作從一個視圖到另一個視圖的導航,就需要使用到Angular中的Router。 【相關教學推薦:《angular教學》】

需要路由跳轉的場景

假如頁面上有兩個跳轉鏈接,我們希望點擊這些鏈接的時候可以分別跳到商品列表頁面個人中心頁面。我們可以先建立兩個元件分別是GoodsListComponentPersonalCenterComponent。具體流程如下所示:

路由建立

#1、新檔案app-routing.module.ts,將會跳轉的視圖配置放到裡面邊

import { NgModule } from '@angular/core'; // 引入路由模块 RouterModule和 Routes import { Routes, RouterModule } from '@angular/router'; // 引入在不同URL下,需要展示的组件 import { GoodsListComponent } from './goods-list/goods-list.component'; import { PersonalCenterComponent } from './personal-center/personal-center.component'; // 配置的路由数组 const routes: Routes = [ { path: 'goodsList', // 定义路由名称 component: GoodsListComponent, // 指定显示的那个组件 }, { path: 'personalCenter', // 定义路由名称 component: PersonalCenterComponent, // 指定显示的那个组件 } ]; @NgModule({ // forRoot() 方法会创建一个 NgModule,其中包含所有指令、给定的路由以及 Router 服务本身。 imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule {}
登入後複製

Routes 陣列中定義你的路由(這個陣列中的每個路由都是一個包含兩個屬性的JavaScript 物件。第一個屬性path 定義了該路由的URL 路徑。第二個屬性component 定義了相對應的路徑下需要顯示的元件)

2、在app.module.ts中導入AppRoutingModule

import { AppRoutingModule } from './app-routing.module';
登入後複製

3、在app.component.html中把這些路由加入進來,以便控制導航的展示

  • 件。
  • 接下來,在範本中加入標籤。這個元素會通知 Angular,你可以用所選路由的元件更新套用的視圖。用法和元件一樣,充當佔位符,用來標記路由器應該把元件顯示到那個位置。

路由中兩個重要API的介紹

#ActivatedRoute

用於 {取得路由資訊}


##,它所包含路由的資訊例如: 路由參數,靜態資料...具體提供的方法可參考
    ActivatedRoute官網
  • import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; // ① 先引入ActivatedRoute @Component({ selector: 'app-goods-list', templateUrl: './goods-list.component.html', styleUrls: ['./goods-list.component.scss'] }) export class GoodsListComponent implements OnInit { constructor( private route: ActivatedRoute, // ② 依赖注入这个服务 ) {} // ③ 在初始化的生命周期中去或者url的路由信息 public ngOnInit(): void { // 第一种获取参数的方式 const params = this.route.snapshot.params; // 第二种获取参数的方式 this.route.params.subscribe(params => { console.log(params); }); } }
    登入後複製
  • #上述兩種取得參數方法的差異與使用:
route.snapshot:

###需要直接存取參數,主要取得###初始值###,不用訂閱的情況下用snapshot;#########route.params.subscribe():###
  • 参数每次变化都要获取到或者需要连续导航多次的时候的用params;

Router

是一个 {提供导航和操纵URL} 的模块,具体提供的方法可参照Router官网,开发中常用到的方法如下,具体讲解在路由传参中会详细介绍:

// 使用前,需要在组件中先引入Router这个服务类 import { Router } from '@angular/router';
登入後複製
  • navigate()该方法支持的参数类型和routerLink指令一样,所以他们的作用也是一样的;

  • navigateByUrl()绝对路由;

  • 每次导航前都会调用events方法;(暂时仅了解)

路由传参以及获取

路由传参的两种形式

1. params (是/:id 动态路由)

使用场景:比如当我们点击商品列表链接时,希望把用户信息,或者商品种类信息通过url,传到商品列表的组件中去。

// 需要配置路由 const routes: Routes = [ { path: 'goodsList/:id', // 定义路由名称 component: GoodsListComponent, // 指定显示的那个组件 }, ];
登入後複製

2. queryParams(是?id=xx 形式)

使用场景:当我们希望通过url传递多个参数的时候,可以选择用这种方式进行路由传参

1个参数可以优先用动态路由,2个以上还是用query更加方便点

路由中传参的3种具体方法

1. routerLink

单一参数:

切换到商品列表组件 // 其中/goodsListl是我设置的路由path,id是需要传递的参数 // 多个参数的时候,也可以用这种形式,只不过看起来不够直观,所以不推荐多个参数的时候也用这种方法
登入後複製

多个参数:

切换到个人中心组件 // 参数的格式可以自行组织成各种object
登入後複製

routerLinkActive跟踪元素上链路路由当前是否处于活动状态。并允许你指定一个或者多个css类,以便在链接路由处于活动状态时添加该元素。

2. router.navigate

基于所提供的命令数组和起点路由进行导航。 如果没有指定起点路由,则从根路由开始进行绝对导航

单一参数:

public goToGoodsListPage(): void { // 第一种方式 this._router.navigate([`/goodsList/${this.id}`]); // 第二种方式 与第一种方式达到相同的效果 this._router.navigate(['/goodsList', this.id]); } // html中调用这个方法,等同于使用a标签的routerLink属性 
登入後複製

多个参数:

public goToPersonalCenterPage(): void { this._router.navigate(['/personalCenter'], {queryParams:{name: 'zs', age: 16}}); } // html中调用 
登入後複製

3. router.navigateByUrl

基于所提供的 URL 进行导航,必须使用绝对路径。对于单一参数和多个参数的使用方法与router.navigate一致。

// 传的第一个参数是数组的形式,而navigate的第一个参数是数组的方式 // 他的传参目前是拼接在url上边的 public goToPersonalCenterPage(): void { this._router.navigateByUrl(`/personalCenter?name=zs&age=16`); }
登入後複製

在路由中接收参数的2种方式

1. 接收params类型的参数

import { ActivatedRoute } from '@angular/router'; constructor( private _route: ActivatedRoute, ) {} public ngOnInit(): void { // 第一种只获取初始值方式 const param = this.route.snapshot.params; // 第二种动态获取方式 this.route.params.subscribe(params => { console.log(params); }); }
登入後複製

2. 接收queryParams类型的参数

import { ActivatedRoute } from '@angular/router'; constructor( private _route: ActivatedRoute, ) {} public ngOnInit(): void { // 第一种只获取初始值方式 const queryParam = this.route.snapshot.queryParams; // 第二种动态获取方式 this.route.queryParams.subscribe(params => { console.log(params); }); }
登入後複製

路由重定向

应用场景:当在一个应用中,希望用户默认跳转到某个页面时,就需要使用得到路由重定向。

重定向的组成:

  • 使用重定向源的path
  • 重定向目标的component
  • pathMatch值来配置路由
{ path: '', redirectTo: '/personalCenter', pathMatch: 'full' }, // 重定向到 `personalCenter`
登入後複製

{pathMatch} 是一个用来 {指定路由匹配策略} 的字符串。可选项有 prefix(默认值)和 full。

prefix: 以指定的路径开头 (就是path中的值与用户输入的的开头路径是一样的,比如path是”abc“,那么用户输入/abc, /abc/a都是可以的,但是输入 /abcd这样就不可以); 如果path是空,那么所有路由都会匹配到这个页面上

full: 与指定路径完全一样(这个就要求与path要求的路径完全一样,比如说path是‘abc’,那么用户输入/abc , /abc/是可以的 /abcd,/abc/d是不可以的); 如果path是空,那么只有localhost:4200后边什么都不加的情况下才匹配到这个页面上。

路由顺序

Router在匹配路由的时候,使用的是” {先到先得} “的策略,所以应当将 {具体的静态的路由} 放前边,然后可以放置 {默认路由匹配} 的空路径路由, {通配符} 路由是最后一个(他可以匹配所以路由,当其他路由都没有匹配对的时候,Router才会选择他)

const routes: Routes = [ // 静态路由 { path: 'goodsList/:id', component: GoodsListComponent, }, { path: 'personalCenter', component: PersonalCenterComponent, }, // 默认空路径路由 { path: '', redirectTo: '/personalCenter', pathMatch: 'full' }, // 通配符路由 { path: '**', component: PageNotFoundComponent }, ];
登入後複製

路由嵌套

當應用程式變的複雜的時候,可能需要創建一些根元件之外的相對路由,這些路由成為子路由,這意味著在專案中需要添加第二個 ##{ } #,因為它是AppComponent 以外的另一個 { }

场景:我们需要在个人中心的页面中,跳转到他的两个子页面中,分别是 {个人配置页面} {个人详情页面} ,具体代码实现如下所示:

import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { GoodsListComponent } from './goods-list/goods-list.component'; import { PersonalCenterComponent } from './personal-center/personal-center.component'; import { PersonalSettingComponent } from './personal-setting/personal-setting.component'; import { PersonalDetailComponent } from './personal-detail/personal-detail.component'; const routes: Routes = [ { path: 'goodsList/:id', component: GoodsListComponent, }, { path: 'personalCenter', component: PersonalCenterComponent, children: [ // 主要是这里添加了一个children数组,用来存放子路由 { path: 'personalDetail', component: PersonalDetailComponent, }, { path: 'personalSetting', component: PersonalSettingComponent, }, ] }, { path: '', redirectTo: '/personalCenter', pathMatch: 'full' }, ]; // 个人中心的html中,需要新增从而来指定子页面展示的位置  
登入後複製

子路由和其它路由一样,同时需要 path 和 component。唯一的区别是你要把子路由放在父路由的children数组中。

路由懒加载

你可以配置路由定义来实现惰性加载模块,这意味着 Angular只会在 {需要时} 才加载这些模块,而不是在应用 {启动时} 就加载全部。

1、先给之前的两个页面组件增加一个module文件,然后routes中使用loadChildren代替component进行配置

import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; const routes: Routes = [ { path: 'goodsList/:id', loadChildren: () => import('./goods-list/goods-list.module') .then(m => m.GoodListModule) }, { path: 'personalCenter', loadChildren: () => import('./personal-center/personal-center.module') .then(m => m.PersonalCenterModule) }, { path: '', redirectTo: '/personalCenter', pathMatch: 'full' }, ]; @NgModule({ // forRoot() 方法会创建一个 NgModule,其中包含所有指令、给定的路由以及 Router 服务本身。 imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule {}
登入後複製

2、在之前的两个页面组件中添加路由模块文件,添加一个指向该组件的路由。

import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { GoodsListComponent } from './goods-list.component'; const routes: Routes = [ { path: '', component: GoodsListComponent }, ]; @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule] }) export class GoodsListRoutingModule { }
登入後複製

路由守卫(仅了解)

使用路由守卫来防止用户未经授权就导航到应用的某些部分,想了解更多请移步路由守卫官网介绍

  • 用CanActivate来处理导航到某路由的情况。 // 进入路由的时候
  • 用CanActivateChild来处理导航到某子路由的情况。
  • 用CanDeactivate来处理从当前路由离开的情况. // 离开路由的时候
  • 用Resolve在路由激活之前获取路由数据。
  • 用CanLoad来处理异步导航到某特性模块的情况。CanActivate仍然会加载某个模块,canload不会去加载当不满足条件的情况下
export class TestGuard implements CanActivate { canActivate( next: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { //判断是否可以进入某个路由的逻辑 } }
登入後複製
{ path: 'test-path', component: TestComponent, canActivate: [TestGuard], // 使用路由守卫guard }
登入後複製

路由事件(仅了解)

Router 在每次导航过程中都会通过 Router.events 属性发出导航事件。这些事件的范围贯穿从导航开始和结束之间的多个时间点。想了解更多请移步

路由事件官网详细介绍

https://angular.cn/guide/router-reference#router-events

#Angular中的表單介紹

響應式表單與範本驅動表單的差異

常用表单公共基础类

响应式表单和模板驱动表单都建立在下列基础类之上。

  • FormControl 实例用于追踪单个表单控件的值和验证状态。

  • FormGroup 用于追踪一个表单控件组的值和状态。

  • FormArray 用于追踪表单控件数组的值和状态。(了解)

模板驱动表单

{依赖} 模板中的 {指令} 来创建和操作底层的对象模型。主要用于添加简单的表单,使用起来较简单,但是扩展性方面不如响应式表单。当控件值更新的时候相关的属性值会被修改为新值。

创建表单

   
登入後複製

模板驱动表单中验证输入

 
姓名的长度不能少于2位
密码不能为空
登入後複製

响应式表单(重点)

提供对 {底层表单对象模型} 直接、显式的访问。它们与模板驱动表单相比,更加健壮,它们的可扩展性、可复用性和可测试性都更高。而且控件更新的 {效率更高} ,因为FormControl 的实例总会返回一个新值,而不会更新现有的数据模型,如果表单是你的应用程序的关键部分,或者可扩展性很强,那就使用响应式表单

使用响应式表单

1、在模块文件中引入响应式表单模块

import { ReactiveFormsModule } from '@angular/forms';
登入後複製

2、在组件中引入表单组

import { FormGroup, FormControl } from '@angular/forms';
登入後複製

3、创建一个FormGroup实例,并把这个FormGroup模型关联到视图

this.profileForm = new FormGroup({ name: new FormControl(''), password: new FormControl(''), });
登入後複製
登入後複製

表单嵌套

表单组可以同时接受 {单个表单控件实例} 和其它表单组实例作为其 {子控件} 。这可以让复杂的表单模型更容易维护,并在逻辑上把它们分组到一起。

1、创建一个嵌套的表单组。

this.profileForm = new FormGroup({ name: new FormControl('', [Validators.required]), password: new FormControl(''), // 在表单中嵌套一个address的表单组 address: new FormGroup({ street: new FormControl(''), city: new FormControl(''), }) });
登入後複製

2、在模板中对这个嵌套表单分组。

// 使用formGroupName来声明新的表单组

Address

登入後複製

表单验证

控件状态的字段

在学习表单验证之前,我们先来了解一下angular针对表单所提供的一些 {状态字段} ,这些字段可帮助用户决定在那些阶段去做表单验证。

  • touched 和 untouched

用来判断用户是否获取过焦点,如果获取过焦点则touched=true; untouched=false,如果从来没有获取过焦点,touched=false; untouched=true。

  • pristine 和 dirty

用来判断用户是否操作过字段,dirty表示用户操作过表单元素,pristine表示未操作过表单元素。

  • valid 和 invalid

判断表单元素是否有效,当表单元素上有多个验证条件事,只有所有的验证条件都满足验证要求valid才是true,只要有一个验证条件不满足,那么invalid这个属性值就是true。

控件状态的CSS 类

Angular 会自动把很多 {控件属性} 作为 {CSS 类} 映射到控件所在的 {元素} 上。你可以使用这些类来 {根据表单} {状态} 给表单 {控件元素} 添加样式。

  • .ng-valid
  • .ng-invalid
  • .ng-pending
  • .ng-pristine
  • .ng-dirty
  • .ng-untouched
  • .ng-touched

场景: 比如我们希望当控件在不满足验证条件的情况下,控件边框显示成红色~ 实现方式如下:

.ng-touched:not(form){ &.ng-invalid:not(form){ // 这是scss的一种写法 border: 1px solid red } }
登入後複製
表单验证的步骤

1、在表单组件中导入一个验证器函数,Angular具体提供了那些内置验证器请参照表单验证器官网

import { Validators } from '@angular/forms'; // angular提供的内置验证器主要有: min max required email minLength maxLength pattern...
登入後複製

2、把这个验证器添加到表单中的相应字段。

场景:需要做验证的内容分别是,① 名称不能为空; ② 密码不能为空,且最小长度不能少于4; ③住址中的街道不能为空

this.profileForm = new FormGroup({ name: new FormControl('', [Validators.required]), password: new FormControl('', [Validators.required, Validators.minLength(4)]), address: new FormGroup({ street: new FormControl('', [Validators.required]), city: new FormControl(''), }) });
登入後複製

3、在模板中错误信息的提醒逻辑

名字是必填项

密码的位数不能少于四位

密码不能为空

Address

街道不能为空
登入後複製
自定义表单验证器

场景:用户希望在填写手机号的时候,可以验证手机号的格式是否输入正确,便可以通过自定义函数去做这件事

public ngOnInit(): void { this.profileForm = new FormGroup({ phone: new FormControl('', [this.mobileValidator]) }); } public mobileValidator = (control: FormControl): any => { const value = control.value; // 手规号码正则 const mobileReg = /^0?(13[0-9]|15[012356789]|17[013678]|18[0-9]|14[57])[0-9]{8}$/; const result = mobileReg.test(value); // 有效值返回null, 无效时返回验证的错误对象,验证对象是名为mobileFormat的验证秘钥属性。值一般可以是任意值 // mobileFormat 用于在模板中获取错误信息的时候会被再次使用 return result ? null : {mobileFormat: {info: '手机格式不正确'}}; } // 在模板中的使用 
{{profileForm?.get('phone').errors | json}}
// 可以将在自定义函数中定义的报错信息打印出来

手机格式不正确

登入後複製

如何更新表单数据

  1. 使用setValue()方法来为单个控件设置新值。 setValue() 方法会严格遵循表单组的结构,并整体性替换控件的值。
  2. 使用patchValue()方法可以用对象中所定义的任何属性为表单模型进行替换。

使用FormBuilder服务生成控件

FormBuilder 服务提供了一些 {便捷方法} 来生成表单控件。FormBuilder 在幕后也使用同样的方式来创建和返回这些实例,只是用起来更简单。

服务有三个方法:control()、group() 和 array()。这些方法都是工厂方法,用于在组件类中分别生成 FormControl、FormGroup 和 FormArray。

1.在组件中引入FormBuilder类,并注入服务

import { FormBuilder } from '@angular/forms'; constructor(private fb: FormBuilder) { }
登入後複製

2.生成表单内容

this.profileForm = this.fb.group({ name: [''], password: [''] }); // 等同于 this.profileForm = new FormGroup({ name: new FormControl(''), password: new FormControl(''), });
登入後複製

跨字段交叉验证(仅了解)

const heroForm = new FormGroup({ 'name': new FormControl(), 'alterEgo': new FormControl(), 'power': new FormControl() }, { validators: identityRevealedValidator }); export const identityRevealedValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null => { const name = control.get('name'); const alterEgo = control.get('alterEgo'); return name && alterEgo && name.value === alterEgo.value ? { identityRevealed: true } : null; };
登入後複製

更多编程相关知识,请访问:编程视频!!

以上是Angular進階學習之深入了解路由與表單的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:juejin.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!
##範本驅動器 建立表單模型 顯示的,在元件類別中建立 隱含的,有指令建立 資料模型 結構化和不可變的(可觀察物件) 非結構化和可變的(資料雙向綁定) #資料流 同步 非同步 #表單驗證 函數 指令

#回應式