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

如何用Flutter Go_Router实现倒L型网页框架?

用GoRouter实现倒L型布局的可行方案

方案思路

倒L型布局核心是顶部固定导航栏 + 左侧固定侧边栏 + 右下内容区,GoRouter的ShellRoute嵌套是最贴合路由设计的实现方式:

  • 外层ShellRoute负责渲染顶部导航栏,将侧边栏+页面内容作为子节点
  • 内层ShellRoute负责渲染左侧侧边栏,将实际页面内容作为子节点

这种嵌套结构能保证路由切换时,顶部、侧边栏常驻,仅内容区更新,完全符合单页应用的路由行为,比Stack+Positioned的纯布局方案更易维护扩展。

完整代码实现

基于你提供的现有代码,修改后实现倒L型布局:

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

// 假设你已定义globals和Header组件
class globals {
  static const Color MenuBarBackgroundColor = Colors.grey;
  static const TextStyle MenuBarStyle = TextStyle(color: Colors.white);
}

class Header extends StatelessWidget {
  const Header({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 100,
      color: Colors.blue,
      child: const Center(child: Text('Header Image')),
    );
  }
}

// 左侧侧边栏组件
class LeftSidebar extends StatelessWidget {
  const LeftSidebar({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 200,
      color: Colors.grey[200],
      child: Column(
        children: [
          TextButton(
            onPressed: () => context.go('/dashboard'),
            child: const Text('Dashboard'),
          ),
          TextButton(
            onPressed: () => context.go('/settings'),
            child: const Text('Settings'),
          ),
          // 更多侧边栏菜单项
        ],
      ),
    );
  }
}

// 示例页面组件
class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return const Center(child: Text('Home Page Content'));
  }
}

class DashboardPage extends StatelessWidget {
  const DashboardPage({super.key});

  @override
  Widget build(BuildContext context) {
    return const Center(child: Text('Dashboard Content'));
  }
}

class SettingsPage extends StatelessWidget {
  const SettingsPage({super.key});

  @override
  Widget build(BuildContext context) {
    return const Center(child: Text('Settings Content'));
  }
}

final GoRouter _router = GoRouter(
  initialLocation: '/',
  routes: [
    // 外层Shell:顶部导航栏
    ShellRoute(
      builder: (context, state, child) {
        final screenWidth = MediaQuery.of(context).size.width;
        final menuSpacing = screenWidth * 0.01;
        return Scaffold(
          body: Padding(
            padding: EdgeInsets.symmetric(horizontal: screenWidth * 0.1),
            child: Column(
              children: [
                const Header(), // 顶部Header
                Container(  // 顶部导航栏
                  height: 50,
                  color: globals.MenuBarBackgroundColor,
                  child: Row(
                    children: [
                      TextButton(
                        onPressed: () => context.go("/"),
                        child: const Text("Home", style: globals.MenuBarStyle),
                      ),
                      SizedBox(width: menuSpacing),
                      TextButton(
                        onPressed: () => context.go("/dashboard"),
                        child: const Text("Dashboard", style: globals.MenuBarStyle),
                      ),
                      // 更多顶部菜单项
                    ],
                  ),
                ),
                Expanded(child: child), // 内层Shell+页面内容在这里渲染
              ],
            ),
          ),
        );
      },
      routes: [
        // 内层Shell:左侧侧边栏
        ShellRoute(
          builder: (context, state, child) {
            return Row(
              children: [
                const LeftSidebar(), // 左侧固定侧边栏
                Expanded(child: child), // 页面内容区
              ],
            );
          },
          routes: [
            // 具体页面路由
            GoRoute(
              path: "/",
              builder: (context, state) => const HomePage(),
            ),
            GoRoute(
              path: "/dashboard",
              builder: (context, state) => const DashboardPage(),
            ),
            GoRoute(
              path: "/settings",
              builder: (context, state) => const SettingsPage(),
            ),
          ],
        ),
      ],
    ),
  ],
);

// 主应用入口
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: _router,
      title: '倒L型布局Demo',
    );
  }
}

关键说明

  1. 嵌套ShellRoute的优势:

    • 层级清晰,外层控顶部、内层控侧边栏,路由逻辑与布局完全分离
    • 路由切换仅更新内容区,导航组件常驻,符合单页应用交互逻辑
    • 后续扩展折叠侧边栏、响应式布局时,代码改动更集中
  2. 布局优化建议:

    • 侧边栏宽度可通过MediaQuery动态计算,适配不同设备
    • 可结合状态管理(如Riverpod)实现侧边栏折叠功能
    • 导航菜单统一用context.go()跳转,保持路由行为一致性
  3. 为什么不选Stack+Positioned:

    • 纯布局方案未结合路由嵌套逻辑,路由复杂时代码耦合度高
    • ShellRoute是GoRouter专为"路由嵌套布局"设计的API,更契合框架设计理念

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 04:07:15