鸿蒙状态管理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示例能帮助兄弟们更好地理解和应用这一强大架构,开发出代码质量上乘的鸿蒙应用!

相关推荐
丘耳3 小时前
vis-network 知识点笔记
前端·javascript
有点笨的蛋3 小时前
重新理解 Flexbox:让布局回归“弹性”的本质
前端·css
小着3 小时前
微信小程序组件中二维码生成问题解决方案
前端·微信小程序
潜心编码3 小时前
基于Django的医疗电子仪器系统
前端·数据库·1024程序员节
摘星编程3 小时前
深入 Actix-web 源码:解密 Rust Web 框架的高性能内核
开发语言·前端·rust·actixweb
小白的码BUG之路3 小时前
Vue3 -- 响应式 ref和 reactive
前端·javascript·vue.js
Onion3 小时前
Vue2日历组件-仿企微日程日历
前端·javascript·vue.js
用户84298142418103 小时前
js中如何隐藏eval关键字?
前端·javascript·后端
chxii3 小时前
前端与Node.js
前端·node.js