HarmonyOS三层架构实战

devtools/2025/3/19 7:22:07/

目录:

    • 1、三层架构项目结构
      • 1.0、三层架构简介
      • 1.1、 common层(主要放一些公共的资源等)
      • 1.2、 features层(主要模块定义的组件以及图片等静态资源)
      • 1.3、 products层(主要放主页面层和一些主要的资源,内部快速入门,课程学习,知识地图等都是模块放在features层)
      • 1.4、MVVM模式
    • 2、products主页面
    • 3、快速入门模块
      • QuickStartPage.ets
      • Banner.ets
      • bufferToString.ets
      • BannerClass.ets
      • EnablementView.ets
      • TutorialView.ets
      • ArticleClass.ets
    • 4、课程学习模块
      • CourseLearning.ets
    • 5、知识地图模块

1、三层架构项目结构

在这里插入图片描述
这里新建三个文件夹不是模块,来构建鸿蒙项目的三层架构。

1.0、三层架构简介

在这里插入图片描述

1.1、 common层(主要放一些公共的资源等)

在这里插入图片描述

1.2、 features层(主要模块定义的组件以及图片等静态资源)

在这里插入图片描述

1.3、 products层(主要放主页面层和一些主要的资源,内部快速入门,课程学习,知识地图等都是模块放在features层)

在这里插入图片描述

1.4、MVVM模式

在这里插入图片描述
在这里插入图片描述

2、products主页面

这里放置的都是一些跟主页面相关的以及入口文件等。

在这里插入图片描述

import { CourseLearning } from '@ohos/learning';
import { KnowledgeMap } from '@ohos/map';
import { QuickStartPage } from '@ohos/quickstart';@Entry
@Component
struct Index {@State currentIndex: number = 0;private tabsController: TabsController = new TabsController();@BuildertabBarBuilder(title: string, targetIndex: number, selectedIcon: Resource, unselectIcon: Resource) {Column() {Image(this.currentIndex === targetIndex ? selectedIcon : unselectIcon).width(24).height(24)Text(title).fontFamily('HarmonyHeiTi-Medium').fontSize(10).fontColor(this.currentIndex === targetIndex ? '#0A59F7' : 'rgba(0,0,0,0.60)').textAlign(TextAlign.Center).lineHeight(14).fontWeight(500)}.width('100%').height('100%').justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center).onClick(() => {this.currentIndex = targetIndex;this.tabsController.changeIndex(targetIndex);})}build() {Tabs({ barPosition: BarPosition.End, controller: this.tabsController }) {TabContent() {QuickStartPage()}.tabBar(this.tabBarBuilder('快速入门', 0, $r('app.media.ic_01_on'), $r('app.media.ic_01_off')))TabContent() {CourseLearning()}.tabBar(this.tabBarBuilder('课程学习', 1, $r('app.media.ic_02_on'), $r('app.media.ic_02_off')))TabContent() {KnowledgeMap()}.tabBar(this.tabBarBuilder('知识地图', 2, $r('app.media.ic_03_on'), $r('app.media.ic_03_off')))}.vertical(false).divider({strokeWidth: 0.5,color: '#0D182431'}).scrollable(false).backgroundColor('#F1F3F5').padding({ top: 36, bottom: 28 })}
}

以前导出模块都是在各模块index.ets文件下导出,现在是products依赖feature模块,在oh-package.json5中如下配置即可引入相关依赖。

在这里插入图片描述
在module.json5中进行权限配置(这里其他模块需要的权限都在products中的这个配置文件中配置即可)。

在这里插入图片描述

3、快速入门模块

在这里插入图片描述

QuickStartPage.ets

import { TutorialView } from '../view/TutorialView';
import { ArticleClass } from '../model/ArticleClass'
import { ArticleDetailPage } from './ArticleDetailPage';
import { Banner } from '../view/Banner';
import { EnablementView } from '../view/EnablementView';
import { BannerDetailPage } from './BannerDetailPage';
import { BannerClass } from '../model/BannerClass';@Component
export struct QuickStartPage {@State message: string = '快速入门';@Provide('articlePathStack') articlePathStack: NavPathStack = new NavPathStack();@BuilderquickStartRouter(name: string, param?: ArticleClass | BannerClass) {if (name === 'articleDetail') {ArticleDetailPage()} else if (name === 'bannerDetailPage') {BannerDetailPage()}}build() {Navigation(this.articlePathStack) {Column() {Text(this.message).fontSize(24).fontWeight(700).width('100%').textAlign(TextAlign.Start).padding({ left: 16 }).fontFamily('HarmonyHeiTi-Bold').lineHeight(33)//此处采用Scroll作为外层容器,是由于其内部内容很有可能会超过屏幕高度,为保证内容显示,可以采用Scroll组件来进行滚动显示。scrollBar设置为BarState.Off,表示关闭滚动时的滚动条显示Scroll() {Column() {//轮播图广告组件Banner()//赋能组件EnablementView()//入门教程TutorialView()}}.layoutWeight(1).scrollBar(BarState.Off).align(Alignment.TopStart)}.width('100%').height('100%').backgroundColor('#F1F3F5')}.navDestination(this.quickStartRouter).hideTitleBar(true).mode(NavigationMode.Stack)}
}

Banner.ets

import { BannerClass } from '../model/BannerClass';
import { bufferToString } from '../util/BufferUtil';@Component
export struct Banner {@Consume('articlePathStack') articlePathStack: NavPathStack;@State bannerList: BannerClass[] = [];aboutToAppear(): void {//在组件初始化时就加载数据this.getBannerDataFromJSON()}//在Banner中,定义一个方法getBannerDataFromJson,并通过ResourceManager获取当前工程目录下rawfile中的json文件内容。//转换内容需要两个步骤://1、将获取的buffer内容转换为字符串//2、将字符串转换为页面数据结构//因为预览器并不支持获取rawfile目录下的文件,所以无法成功获取到保存在rawfile目录下的json文件里的内容。请用真机/模拟器测试,预览器仅支持简单页面的预览getBannerDataFromJSON() {getContext(this).resourceManager.getRawFileContent('BannerData.json').then(value => {this.bannerList = JSON.parse(bufferToString(value)) as BannerClass[];})}clickToDetailPage(item: BannerClass) {this.articlePathStack.pushPathByName('bannerDetailPage', item);}build() {//Swiper组件作为容器可以使轮播图具有轮播的效果Swiper() {ForEach(this.bannerList, (item: BannerClass) => {//$r("字符串类型的")Image($r(item.imageSrc)).objectFit(ImageFit.Contain) //保持宽高比进行缩小或者放大.width('100%').borderRadius(16).padding({ top: 11, left: 16, right: 16 }).onClick(() => {this.clickToDetailPage(item)})}, (item: BannerClass) => item.id)}//autoPlay控制是否自动轮播子组件,loop属性控制是否循环播放,indicator属性自定义导航点的位置和样式.autoPlay(true).loop(true).indicator(new DotIndicator().color('#1a000000').selectedColor('#0A59F7'))}
}

bufferToString.ets

import { util } from '@kit.ArkTS';
//由于ResourceManager获取到的是Uint8Array类型的内容,所以需要将对应的内容转换为字符串,并将字符串解析为对应的数据结构。考虑到其他的文件也会使用这个公共方法,可以新建一个util文件夹,并创建一个BufferUtil文件,实现这个字符串转换方法
export function bufferToString(buffer: Uint8Array): string {let textDecoder = util.TextDecoder.create('utf-8', {ignoreBOM: true});let resultPut = textDecoder.decodeToString(buffer);return resultPut;
}

BannerClass.ets

export class BannerClass {id: string = '';imageSrc: string = '';url: string = ''constructor(id: string, imageSrc: string, url: string) {this.id = idthis.imageSrc = imageSrc;this.url = url;}
}

EnablementView.ets

import { ArticleClass } from '../model/ArticleClass';
import { bufferToString } from '../util/BufferUtil';@Component
export struct EnablementView {@State enablementList: ArticleClass[] = [];@Consume('articlePathStack') articlePathStack: NavPathStack;aboutToAppear(): void {----------this.getEnablementDataFromJSON()}getEnablementDataFromJSON() {getContext(this).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, right: 16 }).width('100%')Grid() {ForEach(this.enablementList, (item: ArticleClass) => {GridItem() {EnablementItem({ enablementItem: item }).onClick(() => {this.articlePathStack.pushPathByName('articleDetail', item)})}}, (item: ArticleClass) => item.id)}.rowsTemplate('1fr').columnsGap(8).scrollBar(BarState.Off).height(169).padding({ top: 2, left: 16, right: 16 })}.margin({ top: 18 })}
}@Component
export struct EnablementItem {@Prop enablementItem: ArticleClass;build() {Column() {Image($r(this.enablementItem.imageSrc)).width('100%')//设置填充效果为cover模式,即保持宽高比进行缩小或者放大,使得图片两边都大于或等于显示边界.objectFit(ImageFit.Cover).height(96).borderRadius({topLeft: 16,topRight: 16})Text(this.enablementItem.title).height(19).width('100%').fontSize(14).textAlign(TextAlign.Start)//textOverFlow属性设置文本超长时的显示方式,在这里我们设置它的值为Ellipsis,表示超长时使用省略号替代.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(160).height(169).borderRadius(16).backgroundColor(Color.White)}
}

TutorialView.ets

import { bufferToString } from '../util/BufferUtil';
import { ArticleClass } from '../model/ArticleClass';@Component
export struct TutorialView {@State tutorialList: ArticleClass[] = [];@Consume('articlePathStack') articlePathStack: NavPathStack;aboutToAppear(): void {this.getTutorialDataFromJSON()}getTutorialDataFromJSON() {getContext(this).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, right: 16 }).width('100%')List({ space: 12 }) {ForEach(this.tutorialList, (item: ArticleClass) => {ListItem() {TutorialItem({ tutorialItem: item }).onClick(() => {this.articlePathStack.pushPathByName('articleDetail', item)})}}, (item: ArticleClass) => item.id)}.scrollBar(BarState.Off).padding({ left: 16, right: 16 })}.margin({ top: 18 }).alignItems(HorizontalAlign.Start)}
}@Component
export 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,表示它们在任意尺寸的设备下自适应占满剩余空间.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)}
}

ArticleClass.ets

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;}
} 

4、课程学习模块

CourseLearning.ets

import { webview } from '@kit.ArkWeb';@Component
export struct CourseLearning {//创建webviewController,开发者后续可以通过该Controller控制Web组件加载的界面private webviewController: webview.WebviewController = new webview.WebviewController();build() {Column() {Web({ src: $rawfile('course_learning/index.html'), controller: this.webviewController }).domStorageAccess(true)}}
}

5、知识地图模块


http://www.ppmy.cn/devtools/168276.html

相关文章

论文精度:Transformers without Normalization

前言 论文题目:Transformers without Normalization 作者:Jiachen Zhu 1,2 , Xinlei Chen 1 , Kaiming He 3 , Yann LeCun 1,2 , Zhuang Liu 1,4,† 论文地址:https://arxiv.org/pdf/2503.10282 摘要 这篇论文探讨了现代神经网络中广泛使用的归一化层是否是必不可少的。…

分区表和分表

分区表(Partitioning) 定义 分区表是将单个表的数据按照某种规则(如范围、列表、哈希等)划分为多个逻辑部分,每个部分称为一个分区。数据仍然存储在一个物理表中,但逻辑上被分割为多个分区。 特点 逻辑…

20250318在ubuntu20.04中安装向日葵

rootrootrootroot-X99-Turbo:~$ sudo dpkg -i SunloginClient_15.2.0.63064_amd64.deb rootrootrootroot-X99-Turbo:~$ sudo apt-get install -f rootrootrootroot-X99-Turbo:~$ sudo dpkg -i SunloginClient_15.2.0.63064_amd64.deb 20250318在ubuntu20.04中安装向日葵 2025/3…

自定义uniapp组件,以picker组件为例

编写目的 本文说明基于vue3定义uniapp组件的关键点: 1、一般定义在components文件夹创建组件,组件与页面已经没有明确的语法格式区别,所以可以与页面的语法保持一致 ; 2、组件定义后使用该组件的页面不需要引用组件即可使用&am…

华为手机新品将采用新屏幕形态,3月20日揭晓谜底

在科技飞速发展的当下,智能手机市场的竞争可谓白热化。各大厂商不断推陈出新,试图在这片红海之中抢占更多份额。而华为,作为其中的佼佼者,一直以创新为驱动,致力于为消费者带来前所未有的体验。年初,华为常务董事、终端BG董事长、智能汽车解决方案BU董事长余承东在社交媒…

深度学习-简介

一、几个概念 (1)what is ai including? 看一张图: 这里注意机器学习和深度学习的关系 (2)机器学习和模式识别有什么区别? 和机器学习同领域的有一个词叫做模式识别,二者有什么区别呢? 机…

【arXiv 2025】卷积加法自注意力CASAtt,轻量且高效,即插即用!

一、论文信息 论文题目:CAS-ViT: Convolutional Additive Self-attention Vision Transformers for Efficient Mobile Applications 中文题目:CAS-ViT:用于高效移动应用的卷积加法自注意力视觉Transformer 论文链接:https://a…

DeepSeek + Excel:数据处理专家 具体步骤

将DeepSeek与Excel结合使用,可显著提升数据处理效率,实现智能化的数据分析、清洗、计算及可视化。以下是具体操作步骤及核心技巧的综合指南: 一、接入DeepSeek的两种主要方法 1. 插件接入法(推荐) 步骤1:…