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

Flutter Web中Router API(go_router)阻止页面回退的替代方案

Flutter Web未保存更改时阻止页面回退的解决方案

一、go_router环境下的替代方案

由于WillPopScope在Web端go_router中存在兼容性问题,可尝试以下两种方法:

1. 使用PopScope组件(Flutter 3.10+)

PopScope是官方替代WillPopScope的组件,Web端go_router可正常使用。通过它拦截回退请求,结合确认弹窗判断是否允许离开:

PopScope(
  canPop: false, // 禁用默认回退逻辑
  onPopInvoked: (bool didPop) async {
    if (!didPop) {
      if (_hasUnsavedChanges) {
        final shouldPop = await showDialog<bool>(
          context: context,
          builder: (_) => AlertDialog(
            title: const Text('确认离开'),
            content: const Text('你有未保存的更改,确定要离开吗?'),
            actions: [
              TextButton(
                onPressed: () => Navigator.pop(context, false),
                child: const Text('取消'),
              ),
              TextButton(
                onPressed: () => Navigator.pop(context, true),
                child: const Text('确定'),
              ),
            ],
          ),
        );

        if (shouldPop == true) {
          context.goBack();
        }
      } else {
        context.goBack();
      }
    }
  },
  child: // 你的页面内容
)

注意:需确保Flutter版本≥3.10,PopScope才会生效。

2. 直接监听浏览器popstate事件

通过dart:html库监听浏览器回退事件,在有未保存更改时阻止默认行为:

import 'dart:html' as html;

@override
void initState() {
  super.initState();
  html.window.addEventListener('popstate', _handleBackPress);
}

@override
void dispose() {
  html.window.removeEventListener('popstate', _handleBackPress);
  super.dispose();
}

void _handleBackPress(html.Event event) {
  if (_hasUnsavedChanges) {
    event.preventDefault(); // 阻止默认回退
    showDialog(
      context: context,
      builder: (_) => AlertDialog(
        title: const Text('确认离开'),
        content: const Text('你有未保存的更改,确定要离开吗?'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('取消'),
          ),
          TextButton(
            onPressed: () {
              Navigator.pop(context);
              context.goBack(); // 用户确认后手动回退
            },
            child: const Text('确定'),
          ),
        ],
      ),
    );
  }
}

这种方式绕开Flutter路由层,直接对接浏览器原生事件,不受go_router的兼容问题影响。

二、使用auto_route实现回退拦截

auto_route内置路由守卫机制,可轻松实现未保存更改的回退拦截,步骤如下:

1. 定义自定义路由守卫

创建守卫类,拦截回退动作并检查未保存状态:

class UnsavedChangesGuard extends AutoRouteGuard {
  final bool Function() hasUnsavedChanges;
  final BuildContext context;

  UnsavedChangesGuard({required this.hasUnsavedChanges, required this.context});

  @override
  void onNavigation(NavigationResolver resolver, StackRouter router) async {
    if (resolver.isBackNavigation && hasUnsavedChanges()) {
      final shouldLeave = await showDialog<bool>(
        context: context,
        builder: (_) => AlertDialog(
          title: const Text('确认离开'),
          content: const Text('你有未保存的更改,确定要离开吗?'),
          actions: [
            TextButton(
              onPressed: () => Navigator.pop(context, false),
              child: const Text('取消'),
            ),
            TextButton(
              onPressed: () => Navigator.pop(context, true),
              child: const Text('确定'),
            ),
          ],
        ),
      );

      resolver.next(shouldLeave == true);
    } else {
      resolver.next(true);
    }
  }
}

2. 为目标页面绑定守卫

在auto_route的路由配置中,给需要拦截的页面添加守卫:

@MaterialAutoRouter(
  routes: [
    AutoRoute(page: HomePage),
    AutoRoute(
      page: EditPage,
      guards: [UnsavedChangesGuard], // 绑定守卫
    ),
  ],
)
class $AppRouter {}

3. 在页面中初始化守卫

在编辑页面中,注册守卫并传入未保存状态的判断逻辑:

class EditPage extends StatefulWidget {
  const EditPage({super.key});

  @override
  State<EditPage> createState() => _EditPageState();
}

class _EditPageState extends State<EditPage> {
  bool _hasUnsavedChanges = false;

  @override
  Widget build(BuildContext context) {
    final routeData = AutoRouteData.of(context);
    routeData.registerGuard(UnsavedChangesGuard(
      hasUnsavedChanges: () => _hasUnsavedChanges,
      context: context,
    ));

    return Scaffold(
      body: TextField(
        onChanged: (_) => setState(() => _hasUnsavedChanges = true),
      ),
    );
  }
}

用户尝试回退时,守卫会自动触发检查,根据用户选择决定是否允许导航。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 09:20:41