🧩 核心三要素:MVVM架构解析

MVVM模式通过职责分离,将应用清晰地划分为三个核心部分,这是其实现解耦的基石:

架构层 职责与定位 在鸿蒙ArkUI中的典型形态
Model (模型) 负责应用的核心数据和业务逻辑,如数据结构定义、网络请求、数据库操作等。它独立于UI,是应用的数据基础。 实体类(如 User)、数据操作类(如 AuthService)、本地/远程数据源。
View (视图) 负责用户界面的展示和交互事件的收集。它应该是“哑巴”的,不包含任何业务逻辑,仅通过绑定显示数据,并通过事件将用户交互通知给ViewModel。 使用 @Component 装饰的UI组件,在 build() 方法中用声明式语法描述UI。
ViewModel (视图模型) 是连接View和Model的桥梁与核心。它负责为View提供展示所需的状态数据,并响应View的事件来调用业务逻辑。ViewModel不知道View的具体存在,仅通过可观察的状态来驱动UI更新。 使用 @State@Observed 等装饰器的类或结构体,持有和管理UI状态。

这三者的理想协作关系,构成了数据驱动的单向流动闭环,其核心流程如下图所示:

🛠️ 从理论到实践:登录场景实战

理解了核心概念后,我们通过一个典型的用户登录场景,来看看如何用代码实现经典的三层分离。

1. Model层:定义数据与业务
Model层专注于纯粹的数据结构和底层服务。

// User.ts - 数据模型
export class User {
  id: string;
  username: string;
  constructor(id: string, username: string) {
    this.id = id;
    this.username = username;
  }
}

// AuthService.ts - 业务服务(模拟网络请求)
export class AuthService {
  async login(username: string, password: string): Promise<User> {
    // 模拟网络请求
    return new Promise((resolve) => {
      setTimeout(() => {
        if (username && password) {
          resolve(new User('001', username));
        }
      }, 1000);
    });
  }
}

2. ViewModel层:承载状态与逻辑
这是MVVM的“大脑”,它持有View的状态,并包含响应用户交互的逻辑。

// LoginViewModel.ts
import { AuthService } from '../model/AuthService';
import { User } from '../model/User';

export class LoginViewModel {
  // 使用 @State 装饰器声明响应式状态(供View绑定)
  @State username: string = '';
  @State password: string = '';
  @State isLoading: boolean = false;
  @State errorMessage: string = '';
  @State currentUser: User | null = null;

  private authService: AuthService = new AuthService();

  // 业务逻辑:处理登录
  async onLogin() {
    if (!this.username || !this.password) {
      this.errorMessage = '用户名或密码不能为空';
      return;
    }
    this.isLoading = true;
    this.errorMessage = '';
    try {
      this.currentUser = await this.authService.login(this.username, this.password);
      // 登录成功,可在此触发页面跳转(通过状态变化驱动)
    } catch (error) {
      this.errorMessage = '登录失败,请检查网络和凭证';
    } finally {
      this.isLoading = false;
    }
  }

  // 业务逻辑:重置表单
  onReset() {
    this.username = '';
    this.password = '';
    this.errorMessage = '';
  }
}

3. View层:声明式UI与数据绑定
View层变得非常轻薄,只负责描述UI和绑定到ViewModel。

// LoginPage.ets
import { LoginViewModel } from '../viewmodel/LoginViewModel';

@Entry
@Component
struct LoginPage {
  // 持有ViewModel实例
  @State viewModel: LoginViewModel = new LoginViewModel();

  build() {
    Column({ space: 20 }) {
      // 双向数据绑定:输入框与ViewModel状态
      TextInput({ placeholder: '用户名' })
        .value(this.viewModel.username)
        .onChange((value: string) => {
          this.viewModel.username = value;
        })
      TextInput({ placeholder: '密码', type: InputType.Password })
        .value(this.viewModel.password)
        .onChange((value: string) => {
          this.viewModel.password = value;
        })

      // 条件渲染:显示错误信息
      if (this.viewModel.errorMessage) {
        Text(this.viewModel.errorMessage)
          .fontColor(Color.Red)
      }

      // 事件委托:按钮点击调用ViewModel逻辑
      Button('登录', { type: ButtonType.Capsule })
        .onClick(() => {
          this.viewModel.onLogin(); // View不处理逻辑,仅委托
        })
        .enabled(!this.viewModel.isLoading) // 绑定状态控制可用性

      // 绑定状态:显示加载中
      if (this.viewModel.isLoading) {
        LoadingProgress()
      }
    }
    .padding(24)
  }
}

📁 项目组织与进阶技巧

一个结构清晰的项目目录是维护MVVM应用的第一步:

src
├── ets
│   ├── pages                    # 页面入口组件
│   │   └── LoginPage.ets
│   ├── views                    # 纯UI组件(可复用)
│   │   ├── components
│   │   └── ...
│   ├── viewmodels               # 视图模型层
│   │   └── LoginViewModel.ets
│   └── models                   # 数据模型层
│       ├── User.ets
│       └── services
│           └── AuthService.ets

提升开发效率与性能的实用技巧:

  • 简化双向绑定:对于 TextInputCheckbox 等标准组件,可以使用 $$ 语法糖简化双向绑定代码。

    // 传统方式
    TextInput({ value: this.viewModel.username })
      .onChange((value) => { this.viewModel.username = value; })
    // 使用 $$ 语法糖
    TextInput({ text: $$this.viewModel.username })

  • 管理复杂状态:对于嵌套对象,使用 @Observed 装饰类,并在View层使用 @ObjectLink 来观察其内部属性的变化,以实现精确更新。

  • 状态共享:根据共享范围,选择合适的工具。@Provide/@Consume 用于跨组件层级共享;LocalStorage 用于页面级共享;AppStorage 用于应用全局状态。

🏗️ 面向复杂场景的架构演进

当页面逻辑异常复杂时,经典的MVVM三层架构可能面临 ViewModel 过重的问题。此时,可以参考社区实践中演进的更精细化模式,例如引入一个专门的 Presenter(协调层) 。

在这种架构下:

  1. View 依然只做数据绑定和事件触发。

  2. ViewModel 职责更纯粹,仅作为“状态容器”,包含用 @State@ObservedV2 等装饰的响应式字段,不包含任何逻辑。

  3. Presenter 作为新的协调层,负责响应View事件、调用多个Biz(业务模块)、并将结果写回ViewModel。它统一管理生命周期、错误处理和异步任务编排。

  4. Biz (Business) 层则负责封装具体的、可复用的业务逻辑单元。

这种 View -> ViewModel <- Presenter -> Biz -> Model 的分层,虽然增加了复杂度,但在大型项目中能更好地实现关注点分离,让每一层的职责更加单一,更易于测试和维护。

💎 总结

在鸿蒙应用开发中采用MVVM模式,绝不仅是遵循一种潮流。其核心价值在于通过 数据驱动UI 和 关注点分离,为你带来切实的好处:清晰的代码结构更强的可测试性(ViewModel和Model可独立于UI进行单元测试),以及更高效的团队协作

建议你从简单的三层模型开始实践,随着项目复杂度的增长,再逐步考虑引入更精细的架构。始终牢记:MVVM是达到“构建可维护高质量应用”这一目的的手段,而非目的本身

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐