Flutter Web:如何用go_router实现点击NavigationRail改URL不跳转新页面
1. 引入依赖
在pubspec.yaml中添加go_router依赖:
dependencies: flutter: sdk: flutter go_router: ^latest_version # 替换为最新版本号
执行flutter pub get完成依赖安装。
2. 定义路由与页面组件
先创建几个示例页面,再配置GoRouter的路由表:
// 示例页面组件 class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext context) { return const Center(child: Text('首页')); } } class ComponentsPage extends StatelessWidget { const ComponentsPage({super.key}); @override Widget build(BuildContext context) { return const Center(child: Text('组件库')); } } class AboutPage extends StatelessWidget { const AboutPage({super.key}); @override Widget build(BuildContext context) { return const Center(child: Text('关于页面')); } } // GoRouter路由配置 final GoRouter _router = GoRouter( routes: [ GoRoute( path: '/', builder: (context, state) => const MainLayout(), routes: [ GoRoute( path: 'components', builder: (context, state) => const ComponentsPage(), ), GoRoute( path: 'about', builder: (context, state) => const AboutPage(), ), ], ), ], );
3. 构建固定NavigationRail的主布局
核心用Row实现左右布局,左侧固定NavigationRail,右侧通过RouterOutlet承载路由页面,确保导航栏始终可见:
class MainLayout extends StatefulWidget { const MainLayout({super.key}); @override State<MainLayout> createState() => _MainLayoutState(); } class _MainLayoutState extends State<MainLayout> { int _selectedIndex = 0; final Map<String, int> _routeIndexMap = { '/': 0, '/components': 1, '/about': 2, }; // 监听路由变化,同步导航栏选中状态 void _syncNavigationIndex() { final currentRoute = GoRouter.of(context).location; setState(() { _selectedIndex = _routeIndexMap[currentRoute] ?? 0; }); } @override void initState() { super.initState(); GoRouter.of(context).addListener(_syncNavigationIndex); } @override void dispose() { GoRouter.of(context).removeListener(_syncNavigationIndex); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: Row( children: [ // 固定左侧的NavigationRail NavigationRail( selectedIndex: _selectedIndex, onDestinationSelected: (index) { setState(() => _selectedIndex = index); // 根据索引跳转对应路由 switch (index) { case 0: context.go('/'); break; case 1: context.go('/components'); break; case 2: context.go('/about'); break; } }, destinations: const [ NavigationRailDestination( icon: Icon(Icons.home_outlined), selectedIcon: Icon(Icons.home), label: Text('首页'), ), NavigationRailDestination( icon: Icon(Icons.widgets_outlined), selectedIcon: Icon(Icons.widgets), label: Text('组件'), ), NavigationRailDestination( icon: Icon(Icons.info_outlined), selectedIcon: Icon(Icons.info), label: Text('关于'), ), ], ), const VerticalDivider(thickness: 1, width: 1), // 右侧内容区域:路由页面容器 Expanded( child: const RouterOutlet(), ), ], ), ); } }
4. 启动应用
在main函数中使用MaterialApp.router配置路由:
void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp.router( title: 'Fixed NavigationRail Demo', theme: ThemeData(primarySwatch: Colors.blue), routerConfig: _router, ); } }
核心逻辑说明
- 固定布局:通过
Row+Expanded实现左侧导航栏固定、右侧内容区域自适应的布局结构。 - 路由与导航同步:监听GoRouter的路由变化事件,自动更新
NavigationRail的选中索引;点击导航项时调用context.go()切换路由,保证URL和选中状态一致。 - URL同步更新:使用
context.go()而非传统的Navigator.push,确保浏览器地址栏URL同步变化,支持地址栏直接导航和Deep Link功能。
内容的提问来源于stack exchange,提问作者SoulCRYSIS
相关产品推荐
相关产品推荐

