🎯 : MVVM V1状态管理 开发模式,看完即懂!

⭐⭐⭐⭐⭐⭐

📢 前言

  • MVVM(Model-View-ViewModel)是一种前端开发中广泛应用的架构模式,通过数据绑定实现视图与业务逻辑的解耦

📌 核心概念

  • Model: 管理/存储业务数据与逻辑,以及数据结构,例如调用API接口curd(增删改查)的接口初始设定

  • View: 呈现用户界面,只要关注组件属性以及事件的改变与现实是否符合UX

  • ViewModel: 作为Model和View的中介层,将Model提供的原始数据进行加工给View进行现实,并且提供交互事件连接Model进行数据流转

🌳 结构图

img

🚀 模式优势

  • 低耦合: 视图与业务逻辑分离,修改UI无需改动底层数据模型
  • 事件驱动模式: 在中介层(ViewModel)规范了可能触发的事件,在(View)中执行对应的事件逻辑,职责清晰,维护性强
  • 更好的分配团队任务: 基于MVVM模式分发模块,使得逻辑模块与UI设计模块可以并行开发,不同部分彼此独立

🔥🔥🔥 实战环节-基础列表点赞开发

🧱 MVVM模式组织结构

├── 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

// 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<ListItemModel> = []

  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

// 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

// 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<ListItemViewModel> 将自己包装成@Observed不然视图无法监听数据变化
@Observed
export class ListViewModelArray extends Array<ListItemViewModel> {
}

@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

// 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

// 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}
]

🎉 成果图

🌍️ 前往gitee仓库

链接

📝 MVVM 架构通过数据绑定简化了视图和模型的交互,使代码结构更加清晰/线性和可维护,让我们可以在灵活性和复杂性之间取得平衡。

🌸🌼🌺

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐