You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spartacus中表单未提交时路由跳转弹窗实现方案咨询

在Spartacus中实现表单未提交时路由跳转触发确认弹窗

问题说明

需要在带有表单的Spartacus页面中实现:当用户未提交表单(表单处于脏状态)并尝试跳转至其他路由时,弹出确认弹窗提示数据可能丢失,确认后才允许离开页面。

现有方案的局限性

  1. 常规Angular Deactivate Guard:
    该方式需要自定义路由配置,会忽略Commerce后台提供的页面布局,导致Spartacus默认的页眉、页脚等全局组件无法正常渲染,且Spartacus不支持为单个组件添加Deactivate Guard。
    示例代码(不适用于Spartacus):

    RouterModule.forChild([
        {
            path: 'xyz',
            component: XYZComponent,
            canDeactivate: mapToCanDeactivate([XYZDeactivateGuard]),
        },
    ])
    
  2. window:beforeunload 事件:
    仅在页面刷新或关闭浏览器时触发,无法拦截Spartacus应用内的路由跳转行为。
    示例代码:

    @HostListener('window:beforeunload', ['$event'])
    check($event: any) {
        if (this.formDirty) {
            $event.returnValue = 'Your data will be lost!';
        }
    }
    

适配Spartacus的可行方案

通过监听Angular路由的NavigationStart事件,结合表单脏状态判断,实现路由跳转前的确认拦截,完全兼容Spartacus的后台布局:

实现代码

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Router, NavigationStart } from '@angular/router';
import { FormGroup, FormBuilder } from '@angular/forms';
import { Subscription } from 'rxjs';
import { filter } from 'rxjs/operators';

@Component({
  selector: 'app-custom-form-page',
  templateUrl: './custom-form-page.component.html',
})
export class CustomFormPageComponent implements OnInit, OnDestroy {
  form: FormGroup;
  isFormDirty = false;
  private navSubscription: Subscription | null = null;
  private pendingNavigationUrl: string | null = null;

  constructor(
    private fb: FormBuilder,
    private router: Router
  ) {
    // 初始化表单
    this.form = this.fb.group({
      fullName: [''],
      contactEmail: [''],
      message: ['']
    });

    // 监听表单脏状态变化
    this.form.valueChanges.subscribe(() => {
      this.isFormDirty = this.form.dirty;
    });
  }

  ngOnInit(): void {
    // 订阅路由导航开始事件
    this.navSubscription = this.router.events.pipe(
      filter(event => event instanceof NavigationStart)
    ).subscribe((event: NavigationStart) => {
      if (this.isFormDirty && !this.pendingNavigationUrl) {
        // 临时阻止路由跳转,避免浏览器历史记录异常
        this.router.navigate([], { skipLocationChange: true }).then(() => {
          this.pendingNavigationUrl = event.url;
          // 弹出原生确认弹窗(也可替换为Spartacus的Dialog组件)
          const confirmLeave = confirm('你输入的数据尚未保存,确定要离开当前页面吗?');
          
          if (confirmLeave) {
            // 用户确认离开,执行跳转
            this.router.navigateByUrl(this.pendingNavigationUrl!);
            this.form.markAsPristine();
            this.isFormDirty = false;
          }
          this.pendingNavigationUrl = null;
        });
      }
    });
  }

  ngOnDestroy(): void {
    // 销毁订阅,避免内存泄漏
    if (this.navSubscription) {
      this.navSubscription.unsubscribe();
    }
  }

  onFormSubmit(): void {
    // 表单提交逻辑
    if (this.form.valid) {
      // ...执行提交操作(调用Spartacus的Commerce API等)
      this.form.markAsPristine();
      this.isFormDirty = false;
    }
  }
}

关键说明

  • 无需自定义路由,完全保留Commerce后台提供的页面布局,页眉页脚可正常显示
  • 通过skipLocationChange: true临时阻止路由变化,避免浏览器历史记录出现无效条目
  • 表单提交后调用markAsPristine()重置脏状态,防止提交后仍触发确认弹窗
  • 可将原生confirm替换为Spartacus的DialogService,实现风格统一的弹窗

内容的提问来源于stack exchange,提问作者Vlasto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 22:13:18