# harmonyOS_mvvmV1Case **Repository Path**: BlocksArchitect/harmony-os_mvvm-v1-case ## Basic Information - **Project Name**: harmonyOS_mvvmV1Case - **Description**: 鸿蒙开发V1状态管理MVVM最小化例子 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-11-09 - **Last Updated**: 2025-11-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### 🎯 : MVVM V1状态管理 开发模式,看完即懂! ⭐⭐⭐⭐⭐⭐ 📢 **前言** - MVVM(Model-View-ViewModel)是一种前端开发中广泛应用的架构模式,通过数据绑定实现视图与业务逻辑的解耦 📌 **核心概念** - **Model:** 管理/存储业务数据与逻辑,以及数据结构,例如调用API接口curd(增删改查)的接口初始设定 - **View:** 呈现用户界面,只要关注组件属性以及事件的改变与现实是否符合UX - **ViewModel:** 作为Model和View的中介层,将Model提供的原始数据进行加工给View进行现实,并且提供交互事件连接Model进行数据流转 🌳 **结构图** ![](https://communityfile-drcn.op.hicloud.com/FileServer/getFile/cmtybbstemp/20251109/cmtybbs/742/855/122/0030086000742855122.20251109133906.60610817937984478837799645929214:20251109143907:2800:52FE6292DCDF62FB93E7FE53DCCCB6D6984F96BCA105D552D0B5C97E9D19A28C.jpg) 🚀 **模式优势** - **低耦合:** 视图与业务逻辑分离,修改UI无需改动底层数据模型 - **事件驱动模式:** 在中介层(ViewModel)规范了可能触发的事件,在(View)中执行对应的事件逻辑,职责清晰,维护性强 - **更好的分配团队任务:** 基于MVVM模式分发模块,使得逻辑模块与UI设计模块可以并行开发,不同部分彼此独立 ### 🔥🔥🔥 **实战环节-基础列表点赞开发** 🧱 **MVVM模式组织结构** ```javascript ├── src │ ├── ets │ │ ├── components │ │ │ ├──model │ │ │ ├── ListItemModel.ets │ │ │ └── ListModel.ets │ │ │ ├──views │ │ │ ├── ListComponent.ets │ │ │ └── ListItemComponent.ets │ │ │ ├──viewModel │ │ │ ├── ListItemViewModel.ets │ │ │ └── ListViewModel.ets │ │ │ ├──ListIndexComp.ets │ │ ├── pages │ │ │ ├── Index.ets │ └── resources │ │ ├── rawfile │ │ │ ├── listsDate.json │ ``` 🧱 **model** ```javascript // model/ListItemModel.ets /** * 接口每项的字段 */ export class ListItemModel { label: string = '' collect: boolean = false } // model/ListModel.ets /** * 提供原始数据和接口API设定 */ import { common } from '@kit.AbilityKit' import { util } from '@kit.ArkTS' import { ListItemModel } from './ListItemModel' export class ListModel { lists: Array = [] async getMockDate(context: common.UIAbilityContext) { const getJson = await context.resourceManager.getRawFileContent('listsDate.json') const textDecoderOptions: util.TextDecoderOptions = { ignoreBOM: true } const textDecoder = util.TextDecoder.create('utf-8', textDecoderOptions) const result = textDecoder.decodeToString(getJson, { stream: false }) this.lists = JSON.parse(result) } } ``` 🧱 **view** ```javascript // view/ListItemComponent.ets /** * 列表项(item) */ import ListItemViewModel from "../viewModel/ListItemViewModel" @Component export struct ListItemComponent { @ObjectLink ListItemViewModel: ListItemViewModel build() { Row() { Text(this.ListItemViewModel.label) Blank() Text() .width(50) .aspectRatio(1) .borderRadius('50%') .backgroundColor(this.ListItemViewModel.collect ? '#ff4cd1d6' : Color.Transparent) .borderWidth(1) .borderColor(Color.Black) .onClick(() => { this.ListItemViewModel.updateIsCollect(this.getUIContext()) }) } .width('100%') .height(80) .padding({ left: 40, right: 20 }) .borderWidth(1) .borderColor(Color.Black) .borderRadius(12) } } // view/ListComponent.ets /** * 列表循环 */ import ListItemViewModel from "../viewModel/ListItemViewModel" import { ListViewModelArray } from "../viewModel/ListViewModel" import { ListItemComponent } from "./ListItemComponent" @Component export struct ListComponent { @ObjectLink ListViewModelArray: ListViewModelArray build() { Column({ space: 4 }) { ForEach(this.ListViewModelArray, (itemModel: ListItemViewModel) => { ListItemComponent({ ListItemViewModel: itemModel }) }) } } } ``` 🧱 **viewModel** ```javascript // viewModel/ListItemViewModel.ets /** * 列表(item)自身的事件定义 */ import { ListItemModel } from "../model/ListItemModel" @Observed export default class ListItemViewModel { @Track label: string = '' @Track collect: boolean = false setItemDate(item: ListItemModel) { this.label = item.label this.collect = item.collect } updateIsCollect(uiContext: UIContext): void { this.collect = !this.collect uiContext.getPromptAction().showToast({ message: this.collect ? '收藏成功' : '取消收藏' }) } } // viewModel/ListViewModel.ets /** * 中介层提供处理的好数据给视图展示 */ import ListItemViewModel from "./ListItemViewModel" import { common } from "@kit.AbilityKit" import { ListModel } from "../model/ListModel" // TODO: 这里需要继承Array 将自己包装成@Observed不然视图无法监听数据变化 @Observed export class ListViewModelArray extends Array { } @Observed export default class ListViewModel { @Track lists: ListViewModelArray = new ListViewModelArray() async getMockDate(context: common.UIAbilityContext) { const result = new ListModel() await result.getMockDate(context) for (let item of result.lists) { let listItemViewModel = new ListItemViewModel() listItemViewModel.setItemDate(item) this.lists.push(listItemViewModel) } } } ``` 🧱 **ListIndexComp** ```javascript // components/ListIndexComp.ets /** * 列表容器 */ import { common } from "@kit.AbilityKit" import { ListComponent } from "./views/ListComponent" import ListViewModel from "./viewModel/ListViewModel" @Component export struct ListIndexComp { private context = this.getUIContext().getHostContext() as common.UIAbilityContext @State listViewModel: ListViewModel = new ListViewModel() async aboutToAppear() { await this.listViewModel.getMockDate(this.context) } build() { ListComponent({ ListViewModelArray: this.listViewModel.lists }) } } ``` 🧱 **listsDate** ```javascript // src/main/resources/rawfile/listsDate.json /** * mock字段 * label 标题 * collect 收藏 */ [ {"label": "后羿", "collect": false}, {"label": "孙尚香", "collect": false}, {"label": "黄忠", "collect": false}, {"label": "马可波罗", "collect": false}, {"label": "公孙离", "collect": false}, {"label": "狄仁杰", "collect": false}, {"label": "敖丙", "collect": false} ] ``` ### 🎉 成果图 ![](https://communityfile-drcn.op.hicloud.com/FileServer/getFile/cmtybbstemp/20251109/cmtybbs/742/855/122/0030086000742855122.20251109141742.76143978624247019847941997373049:20251109151743:2800:3F0D7495BBA728E4448D083C0DE644E725394C08EBCDFC63DE141257D63F940E.gif) 🌸🌼🌺