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

Flutter Web实现Firebase列表项点击跳转至详情页需求

Flutter Web实现Firestore文档点击跳转详情页(含子集合展示)

一、修改列表项,添加点击跳转逻辑

给ListTile添加onTap事件,通过Navigator跳转到详情页并传递当前文档ID(后续用来查询完整数据和子集合),修改后的列表代码如下:

StreamBuilder<QuerySnapshot>(
  stream: FirebaseFirestore.instance.collection('Guests').snapshots(),
  builder: (context, snapshots) {
    if (snapshots.connectionState == ConnectionState.waiting) {
      return const Center(child: CircularProgressIndicator());
    }
    if (snapshots.hasError) {
      return Center(child: Text('加载失败: ${snapshots.error}'));
    }
    return ListView.builder(
      itemCount: snapshots.data!.docs.length,
      itemBuilder: (context, index) {
        final doc = snapshots.data!.docs[index];
        final data = doc.data() as Map<String, dynamic>;

        return ListTile(
          title: Text(
            data['Drug Name'] ?? '无名称',
            maxLines: 1,
            overflow: TextOverflow.ellipsis,
            style: const TextStyle(
              color: Colors.black54,
              fontSize: 20,
              fontWeight: FontWeight.bold,
            ),
          ),
          subtitle: Text(
            data['Drug Serial Number'] ?? '无编号',
            maxLines: 1,
            overflow: TextOverflow.ellipsis,
            style: const TextStyle(
              color: Colors.black54,
              fontSize: 16,
              fontWeight: FontWeight.bold,
            ),
          ),
          // 点击跳转至详情页
          onTap: () {
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (context) => GuestDetailPage(documentId: doc.id),
              ),
            );
          },
        );
      },
    );
  },
)

二、创建详情页组件

新建GuestDetailPage组件,接收文档ID后分别查询主文档数据和子集合数据,自动展示所有字段:

class GuestDetailPage extends StatelessWidget {
  final String documentId;

  const GuestDetailPage({super.key, required this.documentId});

  // 获取主文档实时数据流
  Stream<DocumentSnapshot> getGuestStream() {
    return FirebaseFirestore.instance
        .collection('Guests')
        .doc(documentId)
        .snapshots();
  }

  // 获取子集合实时数据流(替换为你的子集合名称)
  Stream<QuerySnapshot> getSubCollectionStream() {
    return FirebaseFirestore.instance
        .collection('Guests')
        .doc(documentId)
        .collection('subCollection')
        .snapshots();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('详情信息')),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // 展示主文档所有字段
            StreamBuilder<DocumentSnapshot>(
              stream: getGuestStream(),
              builder: (context, snapshot) {
                if (snapshot.connectionState == ConnectionState.waiting) {
                  return const Center(child: CircularProgressIndicator());
                }
                if (snapshot.hasError) {
                  return Text('加载失败: ${snapshot.error}');
                }
                final data = snapshot.data!.data() as Map<String, dynamic>;
                return Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text('主文档信息', style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold)),
                    const SizedBox(height: 12),
                    // 遍历所有字段自动展示
                    ...data.entries.map((entry) {
                      return Padding(
                        padding: const EdgeInsets.symmetric(vertical: 8),
                        child: Row(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Text('${entry.key}: ', style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
                            Expanded(
                              child: Text(entry.value.toString(), style: const TextStyle(fontSize: 16)),
                            ),
                          ],
                        ),
                      );
                    }),
                  ],
                );
              },
            ),
            const SizedBox(height: 24),
            // 展示子集合数据
            StreamBuilder<QuerySnapshot>(
              stream: getSubCollectionStream(),
              builder: (context, snapshot) {
                if (snapshot.connectionState == ConnectionState.waiting) {
                  return const Center(child: CircularProgressIndicator());
                }
                if (snapshot.hasError) {
                  return Text('子集合加载失败: ${snapshot.error}');
                }
                final docs = snapshot.data!.docs;
                return Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text('子集合信息 (共${docs.length}条)', style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold)),
                    const SizedBox(height: 12),
                    if (docs.isEmpty)
                      const Text('暂无子集合数据')
                    else
                      ListView.builder(
                        shrinkWrap: true,
                        physics: const NeverScrollableScrollPhysics(),
                        itemCount: docs.length,
                        itemBuilder: (context, index) {
                          final subData = docs[index].data() as Map<String, dynamic>;
                          return Card(
                            margin: const EdgeInsets.symmetric(vertical: 8),
                            child: Padding(
                              padding: const EdgeInsets.all(12),
                              child: Column(
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: subData.entries.map((entry) {
                                  return Padding(
                                    padding: const EdgeInsets.symmetric(vertical: 4),
                                    child: Row(
                                      crossAxisAlignment: CrossAxisAlignment.start,
                                      children: [
                                        Text('${entry.key}: ', style: const TextStyle(fontWeight: FontWeight.bold)),
                                        Expanded(child: Text(entry.value.toString())),
                                      ],
                                    ),
                                  );
                                }).toList(),
                              ),
                            ),
                          );
                        },
                      ),
                  ],
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

三、关键注意事项

  • 替换代码中的subCollection为你实际的子集合名称;
  • 确保Firestore安全规则允许Web端读取Guests集合及其子集合;
  • 若不需要实时更新,可将StreamBuilder替换为FutureBuilder,用get()方法获取一次性数据;
  • 代码中已对null值做基础处理,可根据需求调整错误提示逻辑。

内容的提问来源于stack exchange,提问作者Mariam Ashraf Abdel Rahman Ahm

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 05:56:06