鸿蒙Next MVVM模式使用
2025-06-27 22:44:22
106次阅读
0个评论
MVVM模式介绍 在应用开发中,UI的更新需要随着数据状态的变化进行实时同步,而这种同步往往决定了应用程序的性能和用户体验。为了解决数据与UI同步的复杂性,ArkUI采用了 Model-View-ViewModel(MVVM)架构模式。MVVM 将应用分为Model、View和ViewModel三个核心部分,实现数据、视图与逻辑的分离。通过这种模式,UI可以随着状态的变化自动更新,无需手动处理,从而更加高效地管理数据和视图的绑定与更新。 Model:负责存储和管理应用的数据以及业务逻辑,不直接与用户界面交互。 View:负责用户界面展示数据并与用户交互,不包含任何业务逻辑。它通过绑定ViewModel层提供的数据来动态更新UI。 ViewModel:负责管理UI状态和交互逻辑。作为连接Model和View的桥梁,ViewModel监控Model数据的变化,通知View更新UI,同时处理用户交互事件并转换为数据操作。 实现目标:点击列表的点赞,刷新当前item的视图,增加点赞信息
先看一个简单例子: 贴一下ViewModel的代码:
@ObservedV2
export default class StudentViewModel{
@Trace name:string=''
}
import StudentViewModel from "./StudentViewModel"
@ObservedV2
export default class ClassViewModel{
@Trace className:string=''
@Trace stus:StudentViewModel[]=[]
addStu(stu:StudentViewModel){
this.stus.push(stu)
}
}
import { SchoolModel } from "../model/SchoolModel";
import ClassViewModel from "./ClassViewModel";
import StudentViewModel from "./StudentViewModel";
import { UIUtils } from "@ohos.arkui.StateManagement";
@ObservedV2
export default class SchoolViewModel{
@Trace cls:ClassViewModel[]=[]
@Trace name:string=''
// 不推荐 实际开发中不可能直接创建观察者数据,可做测试使用
async load(){
let stu1 = new StudentViewModel()
stu1.name='stu1'
let stu2 = new StudentViewModel()
stu2.name='stu2'
let stu3 = new StudentViewModel()
stu3.name='stu3'
let stu4 = new StudentViewModel()
stu4.name='stu4'
let cls1= new ClassViewModel()
cls1.className='cls1'
cls1.stus.push(stu1)
cls1.stus.push(stu2)
let cls2= new ClassViewModel()
cls2.className='cls2'
cls2.stus.push(stu3)
cls2.stus.push(stu4)
let sch = new SchoolViewModel()
sch.name='sch'
sch.cls.push(cls1)
sch.cls.push(cls2)
this.cls=[...sch.cls]
this.name=sch.name
}
async load2(){
let school = new SchoolModel()
//获取到的是非可观察的数据结构,例如从网络获取,本地缓存,数据库等数据
await school.load()
//将非观察数据变为可观察数据
this.cls = UIUtils.makeObserved< ClassViewModel[]>(school.cls) as ClassViewModel[]
this.name = school.name
}
//增加这个方法,调用的StudentViewModel 的 add方法,同样在StudentModel也需要增加同样的方法,否则上面的UIUtils.makeObserved会报错
addStu(stu:StudentViewModel,index:number){
this.cls[index].addStu(stu)
}
}
// Argument of type 'ClassModel[]' is not assignable to parameter of type 'ClassViewModel[]'.
// Property 'addStu' is missing in type 'ClassModel' but required in type 'ClassViewModel'.
export class ClassModel{
className:string=''
stus:StudentModel[]=[]
addStu(stu:StudentModel){
this.stus.push(stu)
}
}
其他类比较简单,就是没有装饰器的基本类,然后看一下View层的实现,使用V2装饰器,监听数据变化,自动刷新view
@Entry
@ComponentV2
struct mvvm{
@Local school:SchoolViewModel = new SchoolViewModel()
async aboutToAppear(){
await this.school.load2()
}
build() {
Column(){
Text('学校:'+this.school.name)
cls({sch:this.school})
}.height('100%').justifyContent(FlexAlign.Center)
}
}
@ComponentV2
struct cls{
@Param @Require sch:SchoolViewModel
@Event add:(stu:StudentViewModel)=>void = (stu:StudentViewModel)=>{}
build() {
Column(){
List(){
ForEach(this.sch.cls,(itm:ClassViewModel,index:number)=>{
ListItem(){
Column(){
Text('班级:'+itm.className).onClick(()=>{
itm.className='修改班级名字'
})
stu({cls:itm})
Button('添加一名学生').onClick(()=>{
let stu = new StudentViewModel()
stu.name='新学生'
this.sch.addStu(stu,index)
})
}
}
})
}
}
}
}
@ComponentV2
export struct stu{
@Param @Require cls:ClassViewModel
build() {
Column(){
Text('学生:')
List(){
ForEach(this.cls.stus,(itm:StudentViewModel)=>{
ListItem(){
Row(){
Text(itm.name)
Button('添加一名学生').onClick(()=>{
let stu = new StudentViewModel()
stu.name='新学生'
this.cls.addStu(stu)
})
}.width('100%').justifyContent(FlexAlign.Center)
}
})
}
Text('一共'+this.cls.stus.length+'名')
Button('清空').onClick(()=>{
this.cls.stus=[]
})
}
}
}
动态列表点赞主要代码: model层的数据获取:
export default class BlogList{
datas:BlogData[] = []
//返回非观察数据
async loadData(context:common.UIAbilityContext){
let getJson = await context.resourceManager.getRawFileContent('动态列表数据.json');
let textDecoderOptions: util.TextDecoderOptions = { ignoreBOM : true };
let textDecoder = util.TextDecoder.create('utf-8',textDecoderOptions);
let result = textDecoder.decodeToString(getJson);
let resultJson : ResponseResult= JSON.parse(result)
let ares :Array<BlogData>= resultJson.data as Array<BlogData>
ares.forEach((tab:BlogData,index:number)=>{
this.datas.push(tab)
})
return this.datas
}
}
viewModel层数据处理:
@ObservedV2
export default class BlogListViewModel{
@Trace datas:BlogDataViewModel[] = []
async loadData(context:common.UIAbilityContext){
//获取model层的数据
let blogList = new BlogList()
await blogList.loadData(context)
//将非观察数据变为可观察数据
this.datas = UIUtils.makeObserved<Array<BlogDataViewModel>>(blogList.datas) as Array<BlogDataViewModel>
}
//增加点赞数据
add(pra:PraiseViewModel,index:number){
this.datas[index].praiseList=[... this.datas[index].praiseList,pra]
}
}
view层主要代码:
list列表展示:
List({ space: 10 }) {
ForEach(this.blogModel.datas,(item:BlogDataViewModel,index:number)=>{
ListItem(){
ItemBlog({ pageInfos: this.pageInfos,blogdata:item,changePraise:(pra:PraiseViewModel)=>{
this.blogModel.add(pra,index)
} })
}
})
}
item 点击:
Text('点赞'+this.blogdata.praiseList.length).fontColor(Color.White).fontSize(16).onClick(()=>{
let praise =new PraiseViewModel()
praise.userId+='1'+Math.random()
praise.userName='11212'
//@Event的回调事件
this.changePraise(praise)
})
00
- 0回答
- 0粉丝
- 0关注
相关话题
- OpenHarmony 设计模式-单例模式
- 鸿蒙Next Text长文本实现展开收起2种模式
- harmony OS NEXT-双向数据绑定MVVM以及$$语法糖介绍
- 鸿蒙开发:适配系统深浅色模式
- 浅谈 发布-订阅模式
- 鸿蒙Next并发线程TaskPool使用
- OpenHarmony 浅谈 发布-订阅模式
- 鸿蒙Next气泡提示(Popup)的使用
- 鸿蒙Next画布Canvas基础使用演示
- 使用DevEcoStudio 开发、编译鸿蒙 NEXT_APP 以及使用中文插件
- 鸿蒙Next轮播组件Swiper使用了解
- 鸿蒙Next层叠布局使用Stack还是RelativeContainer?
- 鸿蒙Next网格布局Grid简单使用
- (五五)ArkTS 跨团队协作开发模式
- (四五)HarmonyOS Design 的设计模式应用