如何在通过路由切换Tab前校验子组件字段,校验不通过时阻止路由跳转
完全可以实现,针对你的场景有两种成熟的实现方案:
方案一:父组件直接调用子组件校验逻辑
适合仅需要控制Next/Prev按钮触发的跳转场景,实现成本最低。
实现步骤
- 首先定义通用校验接口,所有tab对应的子组件都实现该接口
// 定义通用校验接口 export interface TabFormValidatable { // 返回true校验通过,返回false校验不通过,支持异步校验 validate(): boolean | Promise<boolean> | Observable<boolean>; }
- 子组件实现校验接口,写入自己的表单校验逻辑
// 示例:某表单子组件的实现 export class DemoFormComponent implements TabFormValidatable { // 你的业务表单 bizForm: FormGroup = this.fb.group({ name: ['', Validators.required], phone: ['', Validators.pattern(/^1[3-9]\d{9}$/)] }); validate(): boolean { if (this.bizForm.invalid) { // 触发表单所有字段的错误提示 this.bizForm.markAllAsTouched(); // 可以在这里加全局提示,比如“请完善表单后再跳转” return false; } return true; } }
- 修改父组件的模板和逻辑,获取当前激活的子组件实例做校验
- 先给父组件的router-outlet添加模板变量:
<router-outlet #outlet></router-outlet>
- 父组件类中获取router-outlet实例,修改next方法:
import { RouterOutlet } from '@angular/router'; import { firstValueFrom } from 'rxjs'; export class TabParentComponent { @ViewChild('outlet', { static: false }) outlet: RouterOutlet; async next() { if (this.activeLinkIndex === (this.navLinks.length - 1)) return; // 拿到当前激活的子组件实例 const activeComponent = this.outlet?.component as TabFormValidatable; let isValidatePass = true; // 校验子组件表单,没有实现校验方法的组件默认放行 if (activeComponent?.validate) { const validateRes = activeComponent.validate(); // 兼容异步校验场景 if (validateRes instanceof Observable) { isValidatePass = await firstValueFrom(validateRes); } else if (validateRes instanceof Promise) { isValidatePass = await validateRes; } else { isValidatePass = validateRes; } } // 校验不通过直接终止跳转 if (!isValidatePass) return; // 原有跳转逻辑 const locationConfig = this.navLinks.find(d => d.index === (this.activeLinkIndex + 1)) this.router.navigate([`${locationConfig.link}`], { relativeTo: this.route}) } }
方案二:使用CanDeactivate路由守卫
适合全场景拦截,不管是点击Next/Prev按钮、直接点击tab标签、浏览器前进后退、地址栏手动输入地址触发的跳转,都会先触发表单校验,逻辑更严谨。
实现步骤
- 先实现CanDeactivate守卫
import { CanDeactivate } from '@angular/router'; import { TabFormValidatable } from './tab-form-validatable.interface'; export class TabFormGuard implements CanDeactivate<TabFormValidatable> { async canDeactivate(component: TabFormValidatable) { if (!component?.validate) return true; const validateRes = component.validate(); if (validateRes instanceof Observable) { return firstValueFrom(validateRes); } return validateRes; } }
- 在路由配置中给所有tab子路由添加该守卫
const routes: Routes = [ { path: 'tab-parent', component: TabParentComponent, children: [ { path: 'form1', component: DemoForm1Component, canDeactivate: [TabFormGuard] }, { path: 'form2', component: DemoForm2Component, canDeactivate: [TabFormGuard] }, // 其他子路由 ] } ]
- 在模块的providers中注册该守卫即可,不需要修改原有next方法的逻辑,所有跳转都会自动触发校验。
内容的提问来源于stack exchange,提问作者Madara Uchiha
相关产品推荐
相关产品推荐

