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

SwiftUI考勤系统中如何基于ViewModel条件实现页面跳转?

考勤系统页面跳转路由实现方案

针对你当前的需求,我们可以通过路由协议+依赖注入的方式实现MVVM架构下的页面跳转解耦,避免ViewModel直接依赖UI层代码。以下是具体实现步骤:

1. 定义路由协议

先创建一个路由协议,封装页面跳转和弹窗展示的方法,让ViewModel只依赖抽象协议而非具体UI实现:

protocol LoginRouterProtocol {
    // 跳转到员工验证页面
    func navigateToEmployeeValidationScreen()
    // 展示等待提示Toast
    func showEmployeeWaitingToast()
}

2. 实现具体路由类

在UI层(SwiftUI/UIKit)实现该协议,处理实际的页面跳转和UI操作:

SwiftUI 场景实现

class LoginRouter: LoginRouterProtocol {
    private let navigationPath: Binding<NavigationPath>
    
    init(navigationPath: Binding<NavigationPath>) {
        self.navigationPath = navigationPath
    }
    
    func navigateToEmployeeValidationScreen() {
        navigationPath.wrappedValue.append(ValidationScreenTag())
    }
    
    func showEmployeeWaitingToast() {
        var style = ToastStyle()
        style.backgroundColor = UIColor.gray.withAlphaComponent(0.6)
        style.textColor = UIColor.white
        ToastManager.showToast("employee_waiting", duration: ToastManager.LENGHT_LONG, position: .bottom, style: style)
    }
}

// SwiftUI导航所需的页面标识结构体
struct ValidationScreenTag: Hashable {}

UIKit 场景实现

class LoginRouter: LoginRouterProtocol {
    private weak var navigationController: UINavigationController?
    
    init(navigationController: UINavigationController?) {
        self.navigationController = navigationController
    }
    
    func navigateToEmployeeValidationScreen() {
        let validationVC = EmployeeValidationViewController()
        navigationController?.pushViewController(validationVC, animated: true)
    }
    
    func showEmployeeWaitingToast() {
        var style = ToastStyle()
        style.backgroundColor = UIColor.gray.withAlphaComponent(0.6)
        style.textColor = UIColor.white
        ToastManager.showToast("employee_waiting", duration: ToastManager.LENGHT_LONG, position: .bottom, style: style)
    }
}

3. 修改ViewModel,注入路由依赖

在ViewModel中添加路由属性,通过初始化注入,业务逻辑中直接调用协议方法即可:

class LoginViewModel {
    var resultContent: ResultContent?
    private let router: LoginRouterProtocol
    
    // 初始化时注入路由实例
    init(router: LoginRouterProtocol) {
        self.router = router
    }
    
    func fetchUser(cId: String?, eId: Int?) {
        let apiService = RegisterDataSource()
        
        apiService.searchEmployee2(civilId: cId, employeeId: eId) { [weak self] result in
            guard let self = self else { return }
            switch result {
            case .success(let user):
                DispatchQueue.main.async {
                    self.resultContent = user
                }
                guard let regStatusID = self.resultContent?.regStatusID else { return }
                
                if Vontime().key == nil || Vontime().key == "" {
                    if regStatusID == 0 || regStatusID == 1 {
                        // 通过路由跳转页面
                        self.router.navigateToEmployeeValidationScreen()
                    } else if regStatusID == 2 {
                        // 通过路由展示Toast
                        self.router.showEmployeeWaitingToast()
                    }
                }
            case .failure(let error):
                // 可扩展:通过路由展示错误提示
                print("API请求失败:\(error.localizedDescription)")
            }
        }
    }
}

4. 在View层初始化ViewModel和路由

SwiftUI 场景

struct LoginView: View {
    @State private var navigationPath = NavigationPath()
    @StateObject private var loginVM: LoginViewModel
    
    init() {
        let router = LoginRouter(navigationPath: $navigationPath)
        _loginVM = StateObject(wrappedValue: LoginViewModel(router: router))
    }
    
    var body: some View {
        NavigationStack(path: $navigationPath) {
            // 你的UI布局
            Button("Search"){
                loginVM.fetchUser(cId: civil_id, eId: emp_id)
            }
            // 配置导航目的地
            .navigationDestination(for: ValidationScreenTag.self) {
                EmployeeValidationView()
            }
        }
    }
}

UIKit 场景

class LoginViewController: UIViewController {
    private var loginVM: LoginViewModel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let router = LoginRouter(navigationController: self.navigationController)
        loginVM = LoginViewModel(router: router)
    }
    
    @IBAction func searchButtonTapped(_ sender: UIButton) {
        let civilId = civilIdTextField.text
        let empId = empIdTextField.text.flatMap(Int.init)
        loginVM.fetchUser(cId: civilId, eId: empId)
    }
}

方案优势

  • 职责分离:ViewModel专注业务逻辑判断,路由统一处理UI跳转,符合MVVM设计原则
  • 可测试性:单元测试时可以注入Mock路由,无需依赖真实UI环境
  • 扩展性:后续新增页面跳转只需扩展路由协议和实现,无需修改原有业务逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 12:25:30