> 웹 프론트엔드 > JS 튜토리얼 > Angular 고급 학습: 라우팅 및 양식에 대한 심층적인 이해

Angular 고급 학습: 라우팅 및 양식에 대한 심층적인 이해

青灯夜游
풀어 주다: 2021-12-20 15:29:24
앞으로
2389명이 탐색했습니다.

이 글은 Angular에 대한 고급 연구입니다. Angular의 라우팅 및 양식에 대해 자세히 알아보겠습니다. 모두에게 도움이 되기를 바랍니다.

Angular 고급 학습: 라우팅 및 양식에 대한 심층적인 이해

Angular의 라우팅 소개

단일 페이지 애플리케이션에서는 새 페이지를 얻기 위해 서버로 이동할 필요 없이 서로 다른 정의된 뷰(구성 요소) 사이를 앞뒤로 전환해야 합니다. 한 뷰에서 다른 뷰로 이를 달성하려면 뷰의 navigation을 위해 Angular의 Router를 사용해야 합니다. [관련 튜토리얼 추천: "angular tutorial"]

루트 점프가 필요한 장면:

페이지에 점프 링크가 2개 있는 경우 해당 링크를 클릭하면 제품으로 이동할 수 있기를 바랍니다. 목록 페이지개인 센터 페이지. 먼저

GoodsListComponent商品列表页面个人中心页面。我们可以先创建两个组件分别是 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中把这些路由添加进来,以便控制导航的展示

 <div class="route-change-container">
  <a routerLink="/goodsList">切换到商品列表组件</a> <!--routerLink将你定义的路由连接到模板文件中-->
  <a routerLink="/personalCenter">切换到个人中心组件</a>
</div>

<router-outlet></router-outlet>  <!--此指令通过路由来动态加载组件-->
로그인 후 복사
  • 件。
  • 接下来,在模板中添加 <router-outlet> 标签。该元素会通知 Angular,你可以用所选路由的组件更新应用的视图。用法和组件一样,充当占位符,用来标记路由器应该把组件显示到那个位置上。

路由中两个重要API的介绍

ActivatedRoute

用于{获取路由信息},它所包含路由的信息比如: 路由参数,静态数据...具体提供的方法可参照ActivatedRoute官网

import { Component, OnInit } from &#39;@angular/core&#39;;
import { ActivatedRoute } from &#39;@angular/router&#39;; // ① 先引入ActivatedRoute

@Component({
  selector: &#39;app-goods-list&#39;,
  templateUrl: &#39;./goods-list.component.html&#39;,
  styleUrls: [&#39;./goods-list.component.scss&#39;]
})
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:

  • 需要直接访问参数,主要获取初始值
  • PersonalCenterComponent
라는 두 가지 구성 요소를 만들 수 있습니다. 구체적인 프로세스는 다음과 같습니다.

🎜Routing 생성🎜🎜🎜1 새 파일 app-routing.module.ts를 생성합니다. 리디렉션될 보기 구성을 🎜
// 使用前,需要在组件中先引入Router这个服务类
import { Router } from &#39;@angular/router&#39;;
로그인 후 복사
로그인 후 복사
🎜🎜 내에 배치합니다. Routes 배열에서 경로를 정의합니다(이 배열의 각 경로는 두 개의 속성을 포함하는 JavaScript 개체입니다. 첫 번째 속성 경로가 정의됩니다. URL 경로 두 번째 속성 구성 요소는 해당 경로 아래에 표시되어야 하는 구성 요소를 정의합니다.)🎜🎜2. app.module.ts🎜
// 需要配置路由
const routes: Routes = [
 {
   path: &#39;goodsList/:id&#39;, // 定义路由名称
   component: GoodsListComponent, // 指定显示的那个组件
 },
];
로그인 후 복사
로그인 후 복사
🎜3에서 AppRoutingModule을 가져옵니다. .html 탐색 표시를 제어하려면🎜
 <a [routerLink]="[&#39;/goodsList&#39;, id]" routerLinkActive="active-class">切换到商品列表组件</a>
 // 其中/goodsListl是我设置的路由path,id是需要传递的参数   
 // 多个参数的时候,也可以用这种形式,只不过看起来不够直观,所以不推荐多个参数的时候也用这种方法
로그인 후 복사
로그인 후 복사
🎜
  • . 🎜
  • 다음으로 <router-outlet> 태그를 템플릿에 추가하세요. 이 요소는 선택한 경로의 구성 요소로 앱의 보기를 업데이트할 수 있음을 Angular에 알립니다. 사용법은 구성 요소와 동일하며 라우터가 구성 요소를 표시해야 하는 위치를 표시하는 자리 표시자 역할을 합니다. 🎜🎜🎜🎜라우팅의 두 가지 중요한 API 소개🎜🎜

    🎜ActivatedRoute🎜 < /h4>🎜{라우팅 정보 가져오기}: 라우팅 매개변수, 정적 데이터 등의 라우팅 정보가 포함되어 있습니다. 구체적인 방법은 ActivatedRoute 공식 웹사이트🎜🎜
     <a [routerLink]="[&#39;/personalCenter&#39;]" [queryParams]="{name: &#39;zs&#39;, age: 16}">切换到个人中心组件</a>
     // 参数的格式可以自行组织成各种object
    로그인 후 복사
    로그인 후 복사
    🎜🎜매개변수를 얻는 위 두 가지 방법의 차이점과 사용:
    route . snapshot:🎜
    • 주로 초기값을 얻기 위해 매개변수에 직접 액세스해야 합니다. 구독이 필요하지 않은 경우 스냅샷을 사용하세요. 🎜🎜🎜route.params.subscribe():🎜
      • 参数每次变化都要获取到或者需要连续导航多次的时候的用params;

      Router

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

      // 使用前,需要在组件中先引入Router这个服务类
      import { Router } from &#39;@angular/router&#39;;
      로그인 후 복사
      로그인 후 복사
      • navigate() 该方法支持的参数类型和routerLink指令一样,所以他们的作用也是一样的;

      • navigateByUrl() 绝对路由;

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

      路由传参以及获取

      路由传参的两种形式

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

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

      // 需要配置路由
      const routes: Routes = [
       {
         path: &#39;goodsList/:id&#39;, // 定义路由名称
         component: GoodsListComponent, // 指定显示的那个组件
       },
      ];
      로그인 후 복사
      로그인 후 복사

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

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

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

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

      1. routerLink

      单一参数:

       <a [routerLink]="[&#39;/goodsList&#39;, id]" routerLinkActive="active-class">切换到商品列表组件</a>
       // 其中/goodsListl是我设置的路由path,id是需要传递的参数   
       // 多个参数的时候,也可以用这种形式,只不过看起来不够直观,所以不推荐多个参数的时候也用这种方法
      로그인 후 복사
      로그인 후 복사

      多个参数:

       <a [routerLink]="[&#39;/personalCenter&#39;]" [queryParams]="{name: &#39;zs&#39;, age: 16}">切换到个人中心组件</a>
       // 参数的格式可以自行组织成各种object
      로그인 후 복사
      로그인 후 복사

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

      2. router.navigate

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

      单一参数:

      public goToGoodsListPage(): void {
          // 第一种方式
          this._router.navigate([`/goodsList/${this.id}`]);
          // 第二种方式 与第一种方式达到相同的效果
          this._router.navigate([&#39;/goodsList&#39;, this.id]);
        }
        
      // html中调用这个方法,等同于使用a标签的routerLink属性
      <button (click)="goToGoodsListPage()">切换到商品列表组件</button>
      로그인 후 복사

      多个参数:

        public goToPersonalCenterPage(): void {
          this._router.navigate([&#39;/personalCenter&#39;], {queryParams:{name: &#39;zs&#39;, age: 16}});
        }
        
        // html中调用
         <button (click)="goToPersonalCenterPage()">切换到个人中心组件</button>
      로그인 후 복사

      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 &#39;@angular/router&#39;;
      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 &#39;@angular/router&#39;;
      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: &#39;&#39;,
        redirectTo: &#39;/personalCenter&#39;,
        pathMatch: &#39;full&#39; }, // 重定向到 `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: &#39;goodsList/:id&#39;,
          component: GoodsListComponent,
        },
        {
          path: &#39;personalCenter&#39;, 
          component: PersonalCenterComponent,
        },
        // 默认空路径路由
        {
          path: &#39;&#39;,
          redirectTo: &#39;/personalCenter&#39;,
          pathMatch: &#39;full&#39;
        },
        // 通配符路由
        { path: &#39;**&#39;, component: PageNotFoundComponent },
      ];
      로그인 후 복사

      路由嵌套

      애플리케이션이 복잡해지면 루트 구성 요소 외부에 일부 상대 경로를 만들어야 할 수 있으며 이러한 경로는 하위 경로가 됩니다. 즉, 두 번째 경로를 추가해야 합니다. {otero

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

      import { NgModule } from &#39;@angular/core&#39;;
      import { Routes, RouterModule } from &#39;@angular/router&#39;;
      import { GoodsListComponent } from &#39;./goods-list/goods-list.component&#39;;
      import { PersonalCenterComponent } from &#39;./personal-center/personal-center.component&#39;;
      import { PersonalSettingComponent } from &#39;./personal-setting/personal-setting.component&#39;;
      import { PersonalDetailComponent } from &#39;./personal-detail/personal-detail.component&#39;;
      
      const routes: Routes = [
        {
          path: &#39;goodsList/:id&#39;,
          component: GoodsListComponent,
        },
        {
          path: &#39;personalCenter&#39;,
          component: PersonalCenterComponent,
           children: [  // 主要是这里添加了一个children数组,用来存放子路由
            {
              path: &#39;personalDetail&#39;,
              component: PersonalDetailComponent,
            },
            {
              path: &#39;personalSetting&#39;,
              component: PersonalSettingComponent,
            },
           ]
        },
        {
          path: &#39;&#39;,
          redirectTo: &#39;/personalCenter&#39;,
          pathMatch: &#39;full&#39;
        },
      ];
      
      // 个人中心的html中,需要新增<router-outlet>从而来指定子页面展示的位置
      <div class="personal-center-container">
        这是个人中心页面
        <a routerLink="./personalDetail">切换个人详情页面</a>
        <a routerLink="./personalSetting">切换到个人配置页面</a>
      </div>
      <router-outlet></router-outlet>
      로그인 후 복사

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

      路由懒加载

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

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

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

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

      import { NgModule } from &#39;@angular/core&#39;;
      import { Routes, RouterModule } from &#39;@angular/router&#39;;
      import { GoodsListComponent } from &#39;./goods-list.component&#39;;
      
      const routes: Routes = [
        {
          path: &#39;&#39;,
          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: &#39;test-path&#39;,
        component: TestComponent,
        canActivate: [TestGuard], // 使用路由守卫guard
      }
      로그인 후 복사

      路由事件(仅了解)

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

      路由事件官网详细介绍

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

      Angular의 양식 소개

      반응형 양식과 템플릿 기반 양식의 차이점


      반응 형식 템플릿 구동
      폼 모델을 생성하려면 폼 모델을 명시 적으로 생성합니다. 구성 요소 클래스에서 생성되어 데이터 모델을 생성하는 지침
      구조화되고 불변 (관측 가능한 객체) 비구조화 및 변경 가능(데이터 양방향 바인딩)
      데이터 흐름동기화비동기화
      양식 검증함수지시어

      常用表单公共基础类

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

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

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

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

      模板驱动表单

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

      创建表单

      <!--   #form是模板引用变量,他就代表是form整个元素,我们可以在当前模板的任何地方使用模板引用变量。-->
      <!--  这些变量提供了从模块中直接访问元素的能力 -->
      
      <!--  name名称一定要加上 因为表单中的所有组件和控件都应该有名称-->
      <form (ngSubmit)="onSubmit(myform.value);" #myform="ngForm" novalidate>
        <label for="name">姓名: </label>
        <input type="text" name="name" [(ngModel)]="name">
        <label for="password">密码: </label>
        <input type="password" name="password" [(ngModel)]="password">
        <button>提交</button>
      </form>
      로그인 후 복사

      模板驱动表单中验证输入

      <!--假如我们希望给上述的表单做个校验,密码不能为空,名字的长度不能少于2个字符-->
      <form (ngSubmit)="onSubmit(myform);" #myform="ngForm">
        <label for="name">姓名: </label>
        <input type="text" name="name" [(ngModel)]="name" minlength="2">
        <label for="password">密码: </label>
        <input type="password" name="password" [(ngModel)]="password" required>
        <button>提交</button>
        
        <!-- 主要通过hasError方法来实现-->
        <div *ngIf="myform.form.hasError(&#39;minlength&#39;, &#39;name&#39;)">姓名的长度不能少于2位</div>
        <div *ngIf="myform.form.hasError(&#39;required&#39;, &#39;password&#39;)">密码不能为空</div>
      </form>
      로그인 후 복사

      响应式表单(重点)

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

      使用响应式表单

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

      import { ReactiveFormsModule } from &#39;@angular/forms&#39;;
      로그인 후 복사

      2、在组件中引入表单组

      import { FormGroup, FormControl } from &#39;@angular/forms&#39;;
      로그인 후 복사

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

       this.profileForm = new FormGroup({
            name: new FormControl(&#39;&#39;),
            password: new FormControl(&#39;&#39;),
         });
      로그인 후 복사
      <form [formGroup]="profileForm" (ngSubmit)="submitForm(profileForm.value)">
          <label for="name">First Name: </label>
          <input id="name" type="text" formControlName="name">
          
          <label for="password">Last Name: </label>
          <input id="password" type="text" formControlName="password">
          <button>提交</button>
      </form>
      로그인 후 복사

      表单嵌套

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

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

      this.profileForm = new FormGroup({
            name: new FormControl(&#39;&#39;, [Validators.required]),
            password: new FormControl(&#39;&#39;),
            // 在表单中嵌套一个address的表单组
            address: new FormGroup({
              street: new FormControl(&#39;&#39;),
              city: new FormControl(&#39;&#39;),
            })
         });
      로그인 후 복사

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

      <form [formGroup]="profileForm" (ngSubmit)="submitForm(profileForm.value)">
          <label for="name">First Name: </label>
          <input id="name" type="text" formControlName="name">
          <label for="password">Last Name: </label>
          <input id="password" type="text" formControlName="password">
          
          // 使用formGroupName来声明新的表单组
          <div formGroupName="address">
              <h3>Address</h3>
            
              <label for="street">Street: </label>
              <input id="street" type="text" formControlName="street">
            
              <label for="city">City: </label>
              <input id="city" type="text" formControlName="city">
          </div>
          <button>提交</button>
      </form>
      로그인 후 복사

      表单验证

      控件状态的字段

      在学习表单验证之前,我们先来了解一下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 &#39;@angular/forms&#39;;
      // angular提供的内置验证器主要有: min max required email minLength maxLength pattern...
      로그인 후 복사

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

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

      this.profileForm = new FormGroup({
              name: new FormControl(&#39;&#39;, [Validators.required]),
              password: new FormControl(&#39;&#39;, [Validators.required, Validators.minLength(4)]),
              address: new FormGroup({
                street: new FormControl(&#39;&#39;, [Validators.required]),
                city: new FormControl(&#39;&#39;),
              })
          });
      로그인 후 복사

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

      <form [formGroup]="profileForm" (ngSubmit)="submitForm(profileForm.value)">
      <!-- 姓名-->
          <label for="name">姓名: </label>
          <input id="name" type="text" formControlName="name">
           <div [hidden]="profileForm?.get(&#39;name&#39;).valid || profileForm?.get(&#39;name&#39;)?.untouched">
              <p [hidden]="!profileForm.hasError(&#39;required&#39;, &#39;name&#39;)">名字是必填项</p>
          </div>
          
      <!-- 密码-->
          <label for="password">密码: </label>
          <input id="password" type="text" formControlName="password">
           <!-- 先验证密码当密码是合法的或者用户从未操作多的时候,不显示错误信息 -->
           <!-- 然后在根据hasError来判断具体的错误提醒-->
          <div [hidden]="profileForm?.get(&#39;password&#39;).valid || profileForm?.get(&#39;password&#39;)?.untouched">
            <p [hidden]="!profileForm.hasError(&#39;minlength&#39;, &#39;password&#39;)">密码的位数不能少于四位</p>
            <p [hidden]="!profileForm.hasError(&#39;required&#39;, &#39;password&#39;)">密码不能为空</p>
          </div>
      
      <!-- 地址表单组-->
          <div formGroupName="address">
              <h3>Address</h3>
              <label for="street">Street: </label>
              <input id="street" type="text" formControlName="street">
              <div [hidden]="profileForm?.get(&#39;address&#39;)?.get(&#39;street&#39;)?.valid || profileForm?.get(&#39;address&#39;)?.get(&#39;street&#39;)?.untouched">
                  <div [hidden]="!profileForm.hasError(&#39;required&#39;, [&#39;address&#39;, &#39;street&#39;])">街道不能为空</div>
              </div>
              <label for="city">City: </label>
              <input id="city" type="text" formControlName="city">
          </div>
          <button>提交</button>
      </form>
      로그인 후 복사
      自定义表单验证器

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

       public ngOnInit(): void {
        this.profileForm = new FormGroup({
          phone: new FormControl(&#39;&#39;, [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: &#39;手机格式不正确&#39;}};
        }
        
        // 在模板中的使用
        <form [formGroup]="profileForm" (ngSubmit)="submitForm(profileForm.value)">
          <input id="phone" type="text" formControlName="phone">
          <div>{{profileForm?.get(&#39;phone&#39;).errors | json}}</div> // 可以将在自定义函数中定义的报错信息打印出来
          <div [hidden]="profileForm?.get(&#39;phone&#39;).valid || profileForm?.get(&#39;phone&#39;)?.untouched">
              <p [hidden]="!profileForm.hasError(&#39;mobileFormat&#39;, &#39;phone&#39;)">手机格式不正确</p>
          </div>
          <button>提交</button>
      </form>
      로그인 후 복사

      如何更新表单数据

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

      使用FormBuilder服务生成控件

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

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

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

      import { FormBuilder } from &#39;@angular/forms&#39;;
      constructor(private fb: FormBuilder) { }
      로그인 후 복사

      2.生成表单内容

      this.profileForm = this.fb.group({
          name: [&#39;&#39;],
          password: [&#39;&#39;]
        });
        
        // 等同于
        
      this.profileForm = new FormGroup({
        name: new FormControl(&#39;&#39;),
        password: new FormControl(&#39;&#39;),
      });
      로그인 후 복사

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

      const heroForm = new FormGroup({
        &#39;name&#39;: new FormControl(),
        &#39;alterEgo&#39;: new FormControl(),
        &#39;power&#39;: new FormControl()
      }, { validators: identityRevealedValidator });
      
      
      export const identityRevealedValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {
        const name = control.get(&#39;name&#39;);
        const alterEgo = control.get(&#39;alterEgo&#39;);
      
        return name && alterEgo && name.value === alterEgo.value ? { identityRevealed: true } : null;
      };
      로그인 후 복사

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

      위 내용은 Angular 고급 학습: 라우팅 및 양식에 대한 심층적인 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:juejin.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿