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

GoRouter问题:返回上一页面后URL查询参数未清除

GoRouter Web端返回页面后URL查询参数未清除问题

页面返回时URL参数未清除

从页面返回上一页面时,URL中的查询参数并未被清除,Web端URL表现如下:

  • 预期结果:浏览器地址栏显示 #/
  • 实际结果:浏览器地址栏显示 #/?sort=asc

使用版本:go_route: ^6.0.0

复现代码

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:go_router/go_router.dart';

final Map<String, dynamic> _families = {
  "f1": {
    "name": "Doe",
    "people": {
      "p1": {"name": "Jane", "age": 23},
      "p2": {"name": "John", "age": 6}
    }
  },
  "f2": {
    "name": "Wong",
    "people": {
      "p1": {"name": "June", "age": 51},
      "p2": {"name": "Xin", "age": 44}
    }
  }
};

void main() => runApp(App());

/// The main app.
class App extends StatelessWidget {
  /// Creates an [App].
  App({Key? key}) : super(key: key);

  /// The title of the app.
  static const String title = 'GoRouter Example: Query Parameters';

  // add the login info into the tree as app state that can change over time
  @override
  Widget build(BuildContext context) => MaterialApp.router(
        routerConfig: _router,
        title: title,
        debugShowCheckedModeBanner: false,
      );

  late final GoRouter _router = GoRouter(
    initialLocation: '/',
    redirect: (context, state) {
      print('Subloc: ${state.subloc}');
    },
    debugLogDiagnostics: true,
    routerNeglect: true,
    routes: <GoRoute>[
      GoRoute(
        path: '/',
        builder: (BuildContext context, GoRouterState state) {
          return const HomeScreen();
        },
        routes: <GoRoute>[
          GoRoute(
              name: 'family',
              path: 'family/:fid',
              builder: (BuildContext context, GoRouterState state) {
                return FamilyScreen(
                  fid: state.params['fid']!,
                  asc: state.queryParams['sort'] == 'asc',
                );
              }),
        ],
      ),
    ],
  );
}

/// The home screen that shows a list of families.
class HomeScreen extends StatelessWidget {
  /// Creates a [HomeScreen].
  const HomeScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: const Text(App.title),
      ),
      body: ListView(
        children: <Widget>[
          for (final String fid in _families.keys)
            ListTile(
              title: Text(_families[fid]['name']),
              onTap: () {
                context.goNamed(
                  'family',
                  params: {'fid': fid},
                  queryParams: {'sort': 'asc'},
                );
              },
            )
        ],
      ),
    );
  }
}

/// The screen that shows a list of persons in a family.
class FamilyScreen extends StatelessWidget {
  /// Creates a [FamilyScreen].
  const FamilyScreen({required this.fid, required this.asc, Key? key})
      : super(key: key);

  /// The family to display.
  final String fid;

  /// Whether to sort the name in ascending order.
  final bool asc;

  @override
  Widget build(BuildContext context) {
    final Map<String, String> newQueries;
    final List<String> names = _families[fid]['people']
        .values
        .map<String>((dynamic p) => p['name'] as String)
        .toList();
    names.sort();
    if (asc) {
      newQueries = const <String, String>{'sort': 'desc'};
    } else {
      newQueries = const <String, String>{'sort': 'asc'};
    }
    return Scaffold(
      appBar: AppBar(
        title: Text(_families[fid]['name']),
        leading: BackButton(
          onPressed: () {
            GoRouter.of(context).pop();
          },
        ),
        actions: <Widget>[
          IconButton(
            onPressed: () {
              context.goNamed('family',
                  params: <String, String>{'fid': fid},
                  queryParams: newQueries);
            },
            tooltip: 'sort ascending or descending',
            icon: const Icon(Icons.sort),
          )
        ],
      ),
      body: ListView(
        children: <Widget>[
          for (final String name in asc ? names : names.reversed)
            ListTile(
              title: Text(name),
            ),
        ],
      ),
    );
  }
}

解决办法

方式一:修改返回按钮逻辑(推荐)

原代码用pop()返回时,会回到历史栈中的上一条记录,但Family页面内用goNamed替换了当前路由,导致返回时首页URL被带上参数。直接导航到首页路径,确保参数被清除:

leading: BackButton(
  onPressed: () {
    // 替换pop,直接跳转到首页
    context.go('/');
  },
),

方式二:清理首页的查询参数

在HomeScreen的build方法中,检查当前路由是否带有多余参数,若有则自动清理:

@override
Widget build(BuildContext context) {
  final state = GoRouterState.of(context);
  // 若存在查询参数,导航回纯净的首页路径
  if (state.queryParams.isNotEmpty) {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      context.go('/');
    });
  }
  return Scaffold(
    // 原有页面代码...
  );
}

方式三:调整路由配置

当前路由设置了routerNeglect: true,会忽略导航记录,可能导致历史栈异常。若不需要该特性,可将其改为false:

late final GoRouter _router = GoRouter(
  initialLocation: '/',
  redirect: (context, state) {
    print('Subloc: ${state.subloc}');
  },
  debugLogDiagnostics: true,
  routerNeglect: false, // 修改为false
  routes: <GoRoute>[
    // 原有路由配置...
  ],
);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 13:01:22