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

基于GetX的Flutter Web侧边栏与AppBar持久化及浏览器导航处理

解决GetX+Flutter Web中侧边栏/AppBar持久化与浏览器路由响应问题

一、侧边栏与AppBar跨页面持久化方案

核心思路是将AppBar和Drawer固定在父级布局中,仅动态切换Scaffold的body区域内容,避免页面切换时重建顶部和侧边组件。

1. 创建全局状态控制器

用GetX管理当前页面和侧边栏选中状态:

class AppController extends GetxController {
  final RxInt selectedMenuIndex = 0.obs;
  final Rx<Widget> currentPage = const HomePage().obs;

  // 切换页面并同步路由与菜单选中状态
  void switchPage(Widget page, int index, String routeName) {
    currentPage.value = page;
    selectedMenuIndex.value = index;
    Get.offNamed(routeName); // 更新浏览器地址栏路由
  }
}

2. 父级持久化布局

将AppBar、Drawer与可切换的body整合到主布局:

class MainLayout extends GetView<AppController> {
  const MainLayout({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Obx(() => Text(controller.currentPage.value.pageTitle)),
        // 这里的AppBar内容会根据当前页面动态更新,但组件本身不会重建
      ),
      drawer: Drawer(
        child: ListView(
          children: [
            const DrawerHeader(child: Text('系统菜单')),
            ListTile(
              title: const Text('首页'),
              selected: controller.selectedMenuIndex.value == 0,
              onTap: () {
                controller.switchPage(const HomePage(), 0, HomePage.routeName);
                Get.back(); // 关闭抽屉
              },
            ),
            ListTile(
              title: const Text('设置页'),
              selected: controller.selectedMenuIndex.value == 1,
              onTap: () {
                controller.switchPage(const SettingsPage(), 1, SettingsPage.routeName);
                Get.back();
              },
            ),
          ],
        ),
      ),
      // 仅body区域随状态切换,AppBar和Drawer始终保持
      body: Obx(() => controller.currentPage.value),
    );
  }
}

3. 子页面定义

每个子页面需包含路由名称和页面标题:

class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);

  static const routeName = '/home';
  final String pageTitle = '首页';

  @override
  Widget build(BuildContext context) {
    return const Center(child: Text('首页内容'));
  }
}

二、浏览器前进后退按钮响应方案

通过配置GetX路由监听,同步路由变化与AppController的状态,实现浏览器导航操作与页面状态的联动。

1. 全局路由配置

在main函数中配置GetMaterialApp路由,所有子页面路由指向主布局:

void main() {
  Get.put(AppController()); // 初始化全局控制器
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Flutter Web Demo',
      initialRoute: HomePage.routeName,
      getPages: [
        GetPage(name: HomePage.routeName, page: () => const MainLayout()),
        GetPage(name: SettingsPage.routeName, page: () => const MainLayout()),
      ],
      // 监听路由变化,同步更新控制器状态
      onGenerateRoute: (settings) {
        final controller = Get.find<AppController>();
        switch(settings.name) {
          case HomePage.routeName:
            controller.switchPage(const HomePage(), 0, HomePage.routeName);
            break;
          case SettingsPage.routeName:
            controller.switchPage(const SettingsPage(), 1, SettingsPage.routeName);
            break;
        }
        return MaterialPageRoute(builder: (_) => const MainLayout());
      },
    );
  }
}

2. 路由监听增强

在AppController中添加路由监听,确保前进后退时状态完全同步:

class AppController extends GetxController {
  // ... 原有代码

  @override
  void onInit() {
    super.onInit();
    // 监听GetX路由变化,实时同步页面状态
    ever(Get.routing, (route) {
      final currentRoute = route.current;
      if(currentRoute == HomePage.routeName) {
        switchPage(const HomePage(), 0, HomePage.routeName);
      } else if(currentRoute == SettingsPage.routeName) {
        switchPage(const SettingsPage(), 1, SettingsPage.routeName);
      }
    });
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 07:35:22