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

如何在Flutter Web应用中实现始终可见的左侧侧边导航栏?

实现Flutter Web固定左侧侧边导航栏方案

核心思路

别纠结Drawer(它本来是临时抽屉组件,不是为固定侧边栏设计的),也别用全局路由跳转(比如Navigator.push打开新页面)——这就是你之前跳转出问题的原因。正确做法是把侧边栏和主内容放在同一个页面布局里,只切换主内容区域的内容,让侧边栏始终固定在左侧。

具体实现步骤

1. 基础布局结构

用Row做根布局,左侧放固定宽度的侧边栏,右侧用Expanded包裹主内容容器,占满剩余空间:

class MainPage extends StatefulWidget {
  @override
  _MainPageState createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  int _currentIndex = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Row(
        children: [
          // 固定宽度的侧边栏
          SizedBox(width: 260, child: _Sidebar(onItemTap: (index) => setState(() => _currentIndex = index))),
          // 主内容区域,占满剩余空间
          Expanded(child: _MainContent(currentIndex: _currentIndex)),
        ],
      ),
    );
  }
}

2. 自定义侧边栏组件

写一个独立的侧边栏组件,包含导航项,点击时通知父组件切换主内容索引:

class _Sidebar extends StatelessWidget {
  final Function(int) onItemTap;

  const _Sidebar({required this.onItemTap});

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.blueGrey[50],
      child: ListView(
        padding: EdgeInsets.zero,
        children: [
          // 侧边栏头部
          Container(
            padding: EdgeInsets.symmetric(vertical: 24, horizontal: 16),
            child: Text("管理后台", style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600)),
          ),
          // 导航项列表
          ListTile(
            leading: Icon(Icons.dashboard),
            title: Text("仪表盘"),
            onTap: () => onItemTap(0),
            selected: _currentIndex == 0,
            selectedTileColor: Colors.blue[100],
          ),
          ListTile(
            leading: Icon(Icons.shopping_cart),
            title: Text("订单管理"),
            onTap: () => onItemTap(1),
            selected: _currentIndex == 1,
            selectedTileColor: Colors.blue[100],
          ),
          ListTile(
            leading: Icon(Icons.person),
            title: Text("用户管理"),
            onTap: () => onItemTap(2),
            selected: _currentIndex == 2,
            selectedTileColor: Colors.blue[100],
          ),
        ],
      ),
    );
  }
}

3. 主内容切换

用IndexedStack管理不同页面的切换,它会保留每个页面的状态,切换时不会重复重建:

class _MainContent extends StatelessWidget {
  final int currentIndex;

  const _MainContent({required this.currentIndex});

  @override
  Widget build(BuildContext context) {
    return IndexedStack(
      index: currentIndex,
      children: [
        // 仪表盘页面
        Center(child: Text("仪表盘数据展示")),
        // 订单管理页面
        Center(child: Text("订单列表")),
        // 用户管理页面
        Center(child: Text("用户列表")),
      ],
    );
  }
}

额外优化点

  • 如果需要支持浏览器地址栏跳转、前进后退,可以用go_router的嵌套路由功能,把主内容区域作为嵌套路由容器。
  • 侧边栏可以根据屏幕宽度做响应式调整,比如在移动端自动折叠成抽屉,桌面端保持固定展开。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 17:43:27