
- 个人主页:VON
- 文章所属专栏:从0开始的开源鸿蒙6.0.0
- 个人抖音:清洒
上一篇:
目录
2.6、改造EnablementView和TutorialView
一、前言
在上一篇文章中完成了单独页面的创建,并没有进行分层,导致代码十分冗余,如果想要开发更复杂的APP肯定不能这样写,开发过java的都知道分为三层架构,鸿蒙也是这样也是三层架构的模式,本篇文章主要讲解应用架构设计基础------MVVM模式。废话不多说直接开肝!
官方文档:应用架构设计基础------MVVM模式-HarmonyOS应用开发快速入门-Codelabs-华为开发者联盟
二、实践
本章内容并不复杂,主要三层架构模式见下一章
2.1、简述MVVM
MVVM = Model + View + ViewModel模式,其中状态管理模块起到的就是ViewModel的作用,将数据与视图绑定在一起,更新数据的时候直接更新视图。
2.2、改造model文件
model文件夹用于存储数据模型。它表示组件或其他相关业务逻辑之间传输的数据,是对原始数据的进一步处理。
创建文件的时候看清楚,我刚开始就没看清点击的上面那个导致没有创建成功,这里大家注意下。

这里将Class给提取出来放到model文件中。

导出的时候别忘了使用export进行导出然后再直接import导入即可

2.3、改造view文件
view文件夹主要用于存储UI组件,也就是昨天所写的EnablementView.ets和TutorialView.ets以及Banner.ets组件。

直接将index中的代码拿过来即可,这里由于代码量太多了就将代码折叠起来了。

2.4、改造rawfile文件夹
**官方说明:**rawfile目录中的资源文件会被直接打包进应用,不经过编译,也不会被赋予资源文件ID。通过指定文件路径和文件名引用。
第一次听说这个文件,好像是用于存储json数据的文件夹。

可以看到这是原本的数据,我们是用数组进行存储的,现在转为json格式存放再rawfile文件夹里面即可。
json格式的数据想必大家也并不陌生。

接下来引用json数据先定义一个方法getBannerDataFromJson(),并通过ResourceManager获取当前工程目录下rawfile中的json文件内容。
转换内容需要两个步骤:
1、将获取的buffer内容转换为字符串
由于ResourceManager获取到的是Uint8Array类型的内容,所以需要将对应的内容转换为字符串,并将字符串解析为对应的数据结构。考虑到其他的文件也会使用这个公共方法,可以新建一个util文件夹,并创建一个BufferUtil文件,实现这个字符串转换方法。
果然这里需要进行转换

2、将字符串转换为页面数据结构

3、整体逻辑如下

这里的函数不用刻意去记,可以当成一个模板来进行套用,其他两个组件也可以使用此方法来进行转换,只要知道思路即可。
4、页面的生命周期执行流程

2.5、改造Banner
通过上面的生命周期不难发现,aboutToAppear要先于build,做过vue项目的同学应该都清楚,加载页面之前要先获取数据,就像vue中的onMountd(),所以我们这里也要先获取数据

数据获取
**官方解释:**json中数据由于无法使用r()进行资源访问,所以使用的是字符串"app.media.banner_pic0",而在页面中直接声明时,使用的是r('app.media.banner_pic0'),而Image组件是无法直接读取字符串"app.media.banner_pic0"的,所以这里需要进行内容调整。
这里要将imageSrc数据类型修改为string(注意下这里的s是小写)

别忘了ArticleClass类中也要进行修改

这里的图片引用的方式也需要改变下

2.6、改造EnablementView和TutorialView
这两个文件的引用一样,只需要改下名字即可。

三、测试
接下来开始进行真机测试,我这里使用模拟机来进行测试

我这里启动虚拟机的时候出了点问题,因为我的电脑没有开启虚拟化,大家可以参考下面文章来进行查看
关于win11如何打开Hyper-V详解_win11开启hyper-v-CSDN博客

我这里好像无法使用命令行下载,还是直接去官网下载吧

官网下载的是真的慢,因为这是国外的软件
还是用命令行吧,如果上面文章中的命令无法使用的剋试一下这个指令
-
使用 PowerShell 下载打开 PowerShell(管理员模式),执行以下命令下载最新版本的 Hyper 安装包:
# 下载 Hyper 安装文件到当前目录 Invoke-WebRequest -Uri "https://releases.hyper.is/download/win" -OutFile "hyper-setup.exe"
-
命令行安装下载完成后,继续在 PowerShell 中执行安装命令:
# 运行安装程序(会自动执行安装流程) .\hyper-setup.exe
-
**静默安装(可选)**如果需要无界面静默安装,可以添加参数:
.\hyper-setup.exe /S

调试了一下午也是终于调试成功,我这里直接将Hyper上传到网盘了,有需要的朋友可以自行提取。
通过网盘分享的文件:Hyper-Setup-3.4.1.exe
链接: https://pan.baidu.com/s/1OM67IrDC3-_Uffew5nXyIg 提取码: 9f9s
整体效果如下

这里出了点问题
注意:这里千万不能马虎,所有用到图片的地方都要这样引用!!!

四、源码展示
整体结构如下👇:

ArticleClass
export class ArticleClass {
id: string = '';
imageSrc: string = '';
title: string = '';
brief: string = '';
webUrl: string = '';
constructor(id: string, imageSrc: string, title: string, brief: string, webUrl: string) {
this.id = id;
this.imageSrc = imageSrc;
this.title = title;
this.brief = brief;
this.webUrl = webUrl;
}
}
BannerClass
export class BannerClass{
id : string='';
imageSrc : string='';
url : string = 'https://blog.csdn.net/2302_80329073?type=blog';
constructor(id : string,imageSrc : string,url : string) {
this.id = id;
this.imageSrc = imageSrc;
this.url = url;
}
}
Index
import { TutorialView } from '../view/TutorialView';
import { Banner } from '../view/Banner';
import { EnablementView } from '../view/EnablementView';
@Entry
@Component
struct Index {
@State message: string = 'VON';
build() {
Column(){
Text(this.message)
.fontSize(24)
.fontWeight(700)
.width('100%')
.padding({left:16})
.lineHeight(33)
.textAlign(TextAlign.Start)
Scroll(){
Column(){
Banner()
EnablementView()
TutorialView()
}
}
.layoutWeight(1)
.scrollBar(BarState.Off)
.align(Alignment.TopStart)
}
.height('100%')
.width('100%')
.backgroundColor('#f1f1f1')
.padding({top:11,left:16,right:16});
}
}
BufferUtil
import { util } from '@kit.ArkTS';
//将Uint8Array类型的内容转换为字符串
export function bufferToString(buffer: Uint8Array): string {
let textDecoder = util.TextDecoder.create('utf-8', {
ignoreBOM: true
});
let resultPut = textDecoder.decodeToString(buffer);
return resultPut;
}
Banner
import { BannerClass } from '../model/BannerClass'
import { bufferToString } from '../util/BufferUtil';
// Banner组件
@Component
export struct Banner{
@State bannerList:Array<BannerClass> = [];
aboutToAppear(): void {
this.getBannerDataFromJSON();
}
// 获取json数据并转换为对应类型
getBannerDataFromJSON() {
this.getUIContext().getHostContext()?.resourceManager.getRawFileContent('BannerData.json').then(value => {
this.bannerList = JSON.parse(bufferToString(value)) as BannerClass[];
});
}
build() {
Swiper(){
ForEach(this.bannerList,(item:BannerClass,index:number)=>{
Image($r(item.imageSrc))
.objectFit(ImageFit.Contain)
.width('100%')
.height(260)
.borderRadius(16)
},(item:BannerClass,index:number)=>item.id)
}
.autoPlay(true)
.loop(true)
.indicator(
new DotIndicator()
.color('#f1f1f1')
.selectedColor('red')
)
}
}
EnablementView
import { ArticleClass } from '../model/ArticleClass';
import { bufferToString } from '../util/BufferUtil';
@Component
struct EnablementItem{
@Prop enablementItem:ArticleClass;
build() {
Column(){
Image($r(this.enablementItem.imageSrc))
.width('100%')
.objectFit(ImageFit.Cover)
.height(96)
.borderRadius({
topLeft:16,
topRight:16
})
Text(this.enablementItem.title)
.height(19)
.width('100%')
.fontSize(14)
.textAlign(TextAlign.Start)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.maxLines(1)
.fontWeight(400)
.padding({ left: 12, right: 12 })
.margin({ top: 8 })
Text(this.enablementItem.brief)
.height(32)
.width('100%')
.fontSize(12)
.textAlign(TextAlign.Start)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.maxLines(2)
.fontWeight(400)
.fontColor('rgba(0, 0, 0, 0.6)')
.padding({ left: 12, right: 12 })
.margin({ top: 2 })
}
.width(169)
.height(169)
.borderRadius(16)
.backgroundColor(Color.White)
}
}
@Component
export struct EnablementView {
@State enablementList: Array<ArticleClass> = [];
aboutToAppear(): void {
this.getEnablementDataFromJSON();
}
// 获取json数据并转换为对应类型
getEnablementDataFromJSON() {
this.getUIContext().getHostContext()?.resourceManager.getRawFileContent('EnablementData.json').then(value => {
this.enablementList = JSON.parse(bufferToString(value)) as ArticleClass[];
});
}
build() {
Column(){
Text('赋能套件')
.fontColor('#182431')
.fontSize(16)
.fontWeight(500)
.fontFamily('HarmonyHeiTi-medium')
.textAlign(TextAlign.Start)
.padding({ left: 16 })
.margin({ bottom: 8.5 })
Grid() {
ForEach(this.enablementList, (item: ArticleClass) => {
GridItem() {
EnablementItem({ enablementItem: item })
}
}, (item: ArticleClass) => item.id)
}
.rowsTemplate('1fr')
.columnsGap(8)
.scrollBar(BarState.Off)
.height(169)
.padding({ top: 2, left: 16, right: 16 })
}
.margin({top:18})
.alignItems(HorizontalAlign.Start)
.width('100%')
}
}
TutorialView
import { ArticleClass } from '../model/ArticleClass';
import { bufferToString } from '../util/BufferUtil';
@Component
struct TutorialItem {
@Prop tutorialItem :ArticleClass;
build() {
Row(){
Column() {
Text(this.tutorialItem.title)
.height(19)
.width('100%')
.fontSize(14)
.textAlign(TextAlign.Start)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.maxLines(1)
.fontWeight(400)
.margin({ top: 4 })
Text(this.tutorialItem.brief)
.height(32)
.width('100%')
.fontSize(12)
.textAlign(TextAlign.Start)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.maxLines(2)
.fontWeight(400)
.fontColor('rgba(0, 0, 0, 0.6)')
.margin({ top: 5 })
}
.height('100%')
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
.margin({ right: 12 })
Image($r(this.tutorialItem.imageSrc))
.objectFit(ImageFit.Cover)
.height(64)
.width(108)
.borderRadius(16)
}
.width('100%')
.height(88)
.borderRadius(16)
.backgroundColor(Color.White)
.padding(12)
.alignItems(VerticalAlign.Top)
.margin({top: 20})
}
}
@Component
export struct TutorialView {
@State tutorialList: Array<ArticleClass> = [];
aboutToAppear(): void {
this.getTutorialDataFromJSON();
}
// 获取json数据并转换为对应类型
getTutorialDataFromJSON() {
this.getUIContext().getHostContext()?.resourceManager.getRawFileContent('TutorialData.json').then(value => {
this.tutorialList = JSON.parse(bufferToString(value)) as ArticleClass[];
});
}
build() {
Column() {
Text('入门教程')
.fontColor('#182431')
.fontSize(16)
.fontWeight(500)
.fontFamily('HarmonyHeiTi-medium')
.textAlign(TextAlign.Start)
.padding({ left: 16 })
.margin({ bottom: 8.5 })
List({ space: 12 }) {
ForEach(this.tutorialList, (item: ArticleClass) => {
ListItem() {
TutorialItem({ tutorialItem: item })
}
}, (item: ArticleClass) => item.id)
}
.scrollBar(BarState.Off)
.padding({ left: 16, right: 16 })
}
.margin({ top: 18 })
.alignItems(HorizontalAlign.Start)
}
}