鸿蒙状态管理V2实战:从零构建MVVM架构的应用

兄弟们,今天咱们来聊聊鸿蒙开发中的状态管理V2和MVVM架构,通过一个完整的TodoList应用,手把手带大家掌握这个强大的开发模式!

什么是MVVM模式?

在应用开发中,UI的更新需要随着数据状态的变化进行实时同步,这种同步直接影响应用性能和用户体验。为了解决数据与UI同步的复杂性,ArkUI采用了Model-View-ViewModel(MVVM)架构模式。

简单来说:

  • Model:存储和管理应用数据及业务逻辑,不直接与用户界面交互
  • View:负责用户界面展示数据并与用户交互,不包含业务逻辑
  • ViewModel:作为连接Model和View的桥梁,管理UI状态和交互逻辑

状态管理V2装饰器全家福

在开始实战前,先了解下状态管理V2提供的核心装饰器:

  • @Local:管理组件内部状态
  • @Param:实现组件接受外部输入
  • @Event:实现组件对外输出
  • @ObservedV2 + @Trace:实现类属性深度观测
  • @Monitor:监听状态变量变化
  • @Computed:定义计算属性
  • @Builder:实现自定义构建函数

常规实战开始:一步步构建TodoList

第一步:基础静态列表

typescript 复制代码
@Entry
@ComponentV2
struct TodoList {
  build() {
    Column() {
      Text('待办')
        .fontSize(40)
        .margin({ bottom: 10 })
      Text('Task1')
      Text('Task2')
      Text('Task3')
    }
  }
}

这是最基础的版本,任务都是写死的静态数据。

第二步:添加@Local实现状态管理

typescript 复制代码
@Entry
@ComponentV2
struct TodoList {
  @Local isFinish: boolean = false;

  build() {
    Column() {
      Text('待办')
        .fontSize(40)
        .margin({ bottom: 10 })
      Row() {
        Image(this.isFinish ? $r('app.media.finished') : $r('app.media.unfinished'))
          .width(28)
          .height(28)
        Text('Task1')
          .decoration({ type: this.isFinish ? TextDecorationType.LineThrough : TextDecorationType.None })
      }
      .onClick(() => this.isFinish = !this.isFinish)
    }
  }
}

这里使用@Local装饰器管理任务完成状态,点击任务时可以切换完成状态。

第三步:@Param实现组件传参

typescript 复制代码
@ComponentV2
struct TaskItem {
  @Param taskName: string = '';
  @Param @Once isFinish: boolean = false;

  build() {
    Row() {
      Image(this.isFinish ? $r('app.media.finished') : $r('app.media.unfinished'))
        .width(28)
        .height(28)
      Text(this.taskName)
        .decoration({ type: this.isFinish ? TextDecorationType.LineThrough : TextDecorationType.None })
    }
    .onClick(() => this.isFinish = !this.isFinish)
  }
}

通过@Param实现父组件向子组件传递数据,@Once允许在子组件内更新传入的值。

第四步:@Event实现子组件事件传递

typescript 复制代码
@ComponentV2
struct TaskItem {
  @Param taskName: string = '';
  @Param @Once isFinish: boolean = false;
  @Event deleteTask: () => void = () => {};

  build() {
    Row() {
      Image(this.isFinish ? $r('app.media.finished') : $r('app.media.unfinished'))
        .width(28)
        .height(28)
      Text(this.taskName)
        .decoration({ type: this.isFinish ? TextDecorationType.LineThrough : TextDecorationType.None })
      Button('删除')
        .onClick(() => this.deleteTask())
    }
    .onClick(() => this.isFinish = !this.isFinish)
  }
}

@Event装饰器让子组件可以向父组件传递事件,实现真正的双向数据流。

第五步:Repeat优化列表渲染

typescript 复制代码
Repeat<string>(this.tasks)
  .each((obj: RepeatItem<string>) => {
    TaskItem({
      taskName: obj.item,
      isFinish: false,
      deleteTask: () => this.tasks.splice(this.tasks.indexOf(obj.item), 1)
    })
  })

Repeat提供了高效的列表渲染,支持懒加载和非懒加载两种模式,大幅提升性能。

第六步:@ObservedV2和@Trace深度观测

typescript 复制代码
@ObservedV2
class Task {
  taskName: string = '';
  @Trace isFinish: boolean = false;

  constructor (taskName: string, isFinish: boolean) {
    this.taskName = taskName;
    this.isFinish = isFinish;
  }
}

@ObservedV2@Trace组合使用,可以深度观测嵌套对象的属性变化,解决了复杂数据结构的响应式问题。

第七步:@Monitor和@Computed监听与计算

typescript 复制代码
@Monitor('task.isFinish')
onTaskFinished(mon: IMonitor) {
  console.log('任务' + this.task.taskName + '的完成状态从' + mon.value()?.before + '变为了' + mon.value()?.now);
}

@Computed
get tasksUnfinished(): number {
  return this.tasks.filter(task => !task.isFinish).length;
}

@Monitor监听状态变化,@Computed自动计算衍生数据,两者结合让状态管理更加智能。

第八步:AppStorageV2全局状态管理

typescript 复制代码
@Local setting: Setting = AppStorageV2.connect(Setting, 'Setting', () => new Setting())!;

AppStorageV2实现了跨Ability、跨页面的全局状态共享,非常适合应用级别的设置管理。

第九步:PersistenceV2数据持久化

typescript 复制代码
@Local taskList: TaskList = PersistenceV2.connect(TaskList, 'TaskList', () => new TaskList([]))!;

PersistenceV2将数据持久化到设备磁盘,应用重启后数据依然保持,提供了完整的持久化解决方案。

第十步:@Builder组件复用

typescript 复制代码
@Builder function ActionButton(text: string, onClick:() => void) {
  Button(text, { buttonStyle: ButtonStyleMode.NORMAL })
    .onClick(onClick)
    .margin({ left: 10, right: 10, top: 5, bottom: 5 })
}

@Builder装饰器让UI组件可以像函数一样复用,大大提升代码的可维护性。

MVVM架构重构

当应用变得复杂时,我们需要用MVVM模式重构代码,实现真正的关注点分离。

Model层:纯数据逻辑

TaskModel.ets

typescript 复制代码
export default class TaskModel {
  taskName: string = 'Todo';
  isFinish: boolean = false;
}

TaskListModel.ets

typescript 复制代码
export default class TaskListModel {
  tasks: TaskModel[] = [];

  async loadTasks(context: common.UIAbilityContext){
    // 从本地文件加载任务数据
  }
}

Model层只关心数据,不涉及任何UI逻辑。

ViewModel层:业务逻辑处理

TaskViewModel.ets

typescript 复制代码
@ObservedV2
export default class TaskViewModel {
  @Trace taskName: string = 'Todo';
  @Trace isFinish: boolean = false;

  updateIsFinish(): void {
    this.isFinish = !this.isFinish;
  }
}

TaskListViewModel.ets

typescript 复制代码
@ObservedV2
export default class TaskListViewModel {
  @Type(TaskViewModel)
  @Trace tasks: TaskViewModel[] = [];

  finishAll(ifFinish: boolean): void {
    for(let task of this.tasks){
      task.isFinish = ifFinish;
    }
  }
}

ViewModel处理所有业务逻辑,为View层提供准备好的数据。

View层:纯UI展示

ListView.ets

typescript 复制代码
@ComponentV2
export default struct ListView {
  @Param taskList: TaskListViewModel = new TaskListViewModel();
  @Param setting: Setting = new Setting();

  build() {
    Repeat<TaskViewModel>(this.taskList.tasks.filter(task => this.setting.showCompletedTask || !task.isFinish))
      .each((obj: RepeatItem<TaskViewModel>) => {
        TaskItem({
          task: obj.item,
          deleteTask: () => this.taskList.removeTask(obj.item)
        }).margin(5)
      })
  }
}

View层只负责UI渲染和用户交互,所有数据都通过ViewModel获取。

核心优势总结

通过这个完整的TodoList示例,我们可以看到鸿蒙状态管理V2结合MVVM架构的几大优势:

  1. 清晰的职责分离:Model、View、ViewModel各司其职
  2. 强大的响应式系统:数据变化自动触发UI更新
  3. 优秀的性能表现:Repeat、Computed等特性优化渲染
  4. 完善的持久化方案:PersistenceV2提供开箱即用的数据持久化
  5. 灵活的组件通信:Param、Event实现父子组件高效通信
  6. 便捷的全局状态:AppStorageV2轻松管理应用级状态

操作建议

兄弟们在实际项目中应用时,需要注意以下几点:

  1. 合理使用装饰器:根据场景选择合适的装饰器组合
  2. 性能监控:注意Monitor回调中的性能消耗
  3. 测试驱动:ViewModel的纯函数特性非常适合单元测试

MVVM模式配合状态管理V2,确实能够大幅提升鸿蒙应用的开发效率和代码质量。

希望这个TodoList示例能帮助兄弟们更好地理解和应用这一强大架构,开发出代码质量上乘的鸿蒙应用!

相关推荐
mldong5 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排5 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60616 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角7 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!7 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰7 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi9 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen9 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马10 小时前
AI源码分析:拆解模型底层实现逻辑
前端
IT_陈寒10 小时前
React子组件莫名其妙重渲染?你可能漏了这个Hook
前端·人工智能·后端