兄弟们,今天咱们来聊聊鸿蒙开发中的状态管理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架构的几大优势:
- 清晰的职责分离:Model、View、ViewModel各司其职
- 强大的响应式系统:数据变化自动触发UI更新
- 优秀的性能表现:Repeat、Computed等特性优化渲染
- 完善的持久化方案:PersistenceV2提供开箱即用的数据持久化
- 灵活的组件通信:Param、Event实现父子组件高效通信
- 便捷的全局状态:AppStorageV2轻松管理应用级状态
操作建议
兄弟们在实际项目中应用时,需要注意以下几点:
- 合理使用装饰器:根据场景选择合适的装饰器组合
- 性能监控:注意Monitor回调中的性能消耗
- 测试驱动:ViewModel的纯函数特性非常适合单元测试
MVVM模式配合状态管理V2,确实能够大幅提升鸿蒙应用的开发效率和代码质量。
希望这个TodoList示例能帮助兄弟们更好地理解和应用这一强大架构,开发出代码质量上乘的鸿蒙应用!