SwiftUI中NavigationLink无法正常跳转问题求助
问题根源
你的代码核心错误是将Button嵌套在NavigationLink的label中,点击时会同时触发两个逻辑:
- NavigationLink立即执行页面跳转
- Button执行Firebase异步上传
这就导致还没等数据上传完成,页面已经跳转到UserDashboard,完全违背了“先上传再跳转”的需求,同时这种嵌套交互控件的写法本身就不符合SwiftUI的设计规范。
解决方案:使用编程式导航
我们需要通过状态变量控制导航时机,确保只有在Firebase上传成功后才触发跳转,具体步骤如下:
- 添加导航状态变量
在视图的@State属性中新增一个布尔变量,用于控制导航是否触发:
@State private var shouldNavigateToDashboard = false
- 替换原NavigationLink为状态控制的隐藏版本
将原来的嵌套式NavigationLink替换为受状态变量控制的隐藏链接,放在视图的VStack或ScrollView外层(确保它在NavigationStack范围内):
// 放在ScrollView之后、VStack内部 NavigationLink( destination: UserDashboard().navigationBarBackButtonHidden(true), isActive: $shouldNavigateToDashboard, label: { EmptyView() } )
- 重构“Enregistrer”按钮为独立控件
移除原有的NavigationLink嵌套,直接使用Button执行上传逻辑,在上传成功后修改状态变量触发导航:
Button { let prospect = ProspectModel() Task { do { // 等待Firebase上传完成 try await prospect.enregistrementProspect( service: service, categorie: categorie, nom: nom, email: email, tel: tel, adress: adress, siret: siret ) // 上传成功后触发导航 shouldNavigateToDashboard = true } catch { // 可在此添加错误处理,比如弹窗提示用户上传失败 print("Prospect上传失败:\(error.localizedDescription)") } } } label: { HStack { Text("Enregistrer").fontWeight(.semibold) Image(systemName: "arrow.right") } .foregroundColor(.white) .frame(maxWidth: .infinity, minHeight: 48) } .background(Color(.systemBlue)) .cornerRadius(10) .padding(.top, 24)
完整修改后的代码
import SwiftUI import Firebase struct UserProspect: View { @State private var service = "" @State private var categorie = "" @State private var nom = "" @State private var email = "" @State private var tel = "" @State private var adress = "" @State private var siret = "" // 新增导航控制状态 @State private var shouldNavigateToDashboard = false @EnvironmentObject var viewModel: AuthViewModel var body: some View{ content } var content: some View { NavigationStack { VStack(spacing: 0) { Rectangle() .fill(LinearGradient(colors: [.blue, .teal], startPoint: .topLeading, endPoint: .bottomTrailing)) .frame(height: 140).offset(y:-60) .overlay( Text("Recommandation") .foregroundColor(.white) .font(.system(size: 38, weight: .bold, design: .rounded)) .padding(.top, -50) ) .padding(.bottom, 0) ScrollView { VStack(alignment: .leading, spacing: 10) { SelectorView(title: "Type Service", service: $service, pro: "Professionnel", part: "Particulier") SelectorView(title: "Type de categorie", service: $categorie, pro: "Déménagement", part: "Transport") InputView(text: $nom, title: "Nom", placeholder: "Nom à contacter") InputView(text: $email, title: "Email", placeholder: "Email à contacter") InputView(text: $tel, title: "Téléphone", placeholder: "Téléphone à contacter") InputView(text: $adress, title: "Adresse", placeholder: "Adresse complète") if service == "Professionnel" { InputView(text: $siret, title: "Siret", placeholder: "Siret de l'entreprise") } // 重构后的独立按钮 Button { let prospect = ProspectModel() Task { do { try await prospect.enregistrementProspect( service: service, categorie: categorie, nom: nom, email: email, tel: tel, adress: adress, siret: siret ) shouldNavigateToDashboard = true } catch { print("上传失败:\(error.localizedDescription)") } } } label: { HStack { Text("Enregistrer").fontWeight(.semibold) Image(systemName: "arrow.right") } .foregroundColor(.white) .frame(maxWidth: .infinity, minHeight: 48) } .background(Color(.systemBlue)) .cornerRadius(10) .padding(.top, 24) NavigationLink { ContentView().navigationBarBackButtonHidden(true) } label: { Text("Je n'ai finalement pas d'enregistrement") .fontWeight(.bold) .font(.system(size: 14)) .frame(maxWidth: .infinity, alignment: .center) } } .padding(.horizontal) } // 隐藏的状态控制导航链接 NavigationLink( destination: UserDashboard().navigationBarBackButtonHidden(true), isActive: $shouldNavigateToDashboard, label: { EmptyView() } ) } .background(Color.white.ignoresSafeArea()) .navigationBarHidden(true) } } } struct UserProspect_Previews: PreviewProvider { static var previews: some View{ UserProspect() } }
补充说明
页面中的两个NavigationLink本身不会导致运行问题,第二个链接的写法是正确的(因为它不需要异步操作,直接触发跳转)。核心问题出在第一个链接的嵌套写法上,改用编程式导航后就能实现“先上传再跳转”的需求。
内容的提问来源于stack exchange,提问作者Windows Frame
相关产品推荐
相关产品推荐

