
- 个人主页:VON
- 文章所属专栏:从0开始的开源鸿蒙6.0.0
- 个人抖音:清洒
目录
一、前言
经过前四篇文章的学习相信大家已经具备一定的开发能力的,现在来参考官方文档完成一个简易页面的创建,这是官方文档给出的示意图,简单分析下可以看出也就三部分组成,相信对于大家来说问题不大,我这里还是以文档为主进行学习。
废话不多说开始实践。

二、实践
本章节内容参考官方链接
我这里不知道为啥直接使用preview会这样,所以还是在default中观看吧

我这里将KnowledgeMap组件导出了直接在default中进行展示的
导出这部分就不过多介绍了,就是在map模块中的index文件直接导出即可
export { KnowledgeMap } from './src/main/ets/pages/KnowledgeMap';

2.1、Banner区域
文字区域就不多说了,直接从Banner区域进行讲解,不知道为什么这里目录不完整,目录结构和我的统一下,放一张图片用于展示Banner区域,当然也可以和之前一样弄轮播图进行展示

整体的实现效果如下:

这里主要是Banner和简介区域,这段感觉完全可以提取出来
@Component
export struct KnowledgeMap{
build() {
Column(){
Text('知识地图')
.fontFamily('HarmonyHeiTi-Bold')
.fontSize(24)
.fontColor(Color.Black)
.textAlign(TextAlign.Start)
.lineHeight(33)
.fontWeight(700)
.width('100%')
Image($r('app.media.img'))
.width('100%')
.height('30%')
.borderRadius(16)
.margin({ top: 19, bottom: 8 })
Text('她扎着低马尾,碎发贴在耳侧,白衬衫领口别着小珍珠别针。笑时会抿下嘴角,说起花艺眼睛亮,像盛着春日花园。')
.fontFamily('HarmonyHeiTi')
.fontSize(14)
.fontColor('rgba(0,0,0,0.60)')
.fontWeight(400)
.textAlign(TextAlign.Start)
}
.padding({ top: 12, right: 16, bottom: 12, left: 16})
.backgroundColor('#F1F3F5')
}
}
2.2、List区域
这里的List区域又两种方法来实现
**官方解释:**一种是使用@Component来自定义组件,另外一种是使用@Builder自定义构建函数,两者各自特点如下:
- @Component功能更加多样,有自己的生命周期,还能支持预览效果。
- 而@Builder更加轻量,能满足基础的组件封装,性能更好,但是不支持预览。
此处为了呈现预览效果,采用了@Component进行定义。如果需要更好的性能的建议采用@Builder的方式进行组件定义封装。
这里直接添加List组件即可,这段代码主要就是要明白数据获取的逻辑
List({ space: 12 }) {
ForEach(this.navBarList, (item: NavBarItemType, index: number) => {
ListItem() {
NavBarItem({ navBarItem: item })
}
.width('100%')
}, (item: NavBarItemType): string => item.title)
}
这里的父组件定义好数据NavBarItemType类型的数据,用数组来接受数据,ForEach遍历数据,将数据传入NavBarItem组件来进行渲染操作。

这里的NavBarItem组件逻辑如下👇:
应该可以理解吧,这里的逻辑并不是很复杂
export interface NavBarItemType {
order: string,
title: string
}
@Component
export struct NavBarItem{
@Prop navBarItem: NavBarItemType;
build() {
Row(){
Text(this.navBarItem.order)
.margin({ right: 6 })
.fontFamily('HarmonyHeiTi-Bold')
.fontSize(21)
.fontColor('#182431')
.textAlign(TextAlign.Start)
.lineHeight(22)
.fontWeight(700)
Text(this.navBarItem.title)
.fontFamily('HarmonyHeiTi-Medium')
.fontSize(16)
.fontColor('#182431')
.textAlign(TextAlign.Start)
.lineHeight(22)
.fontWeight(500)
Blank()//此处采用Blank组件,该组件可以自动填充主轴方向的空余空间
Image($r('app.media.right'))
.width(12)
.height(24)
}
.width('100%')
.height(48)
.borderRadius(16)
.alignItems(VerticalAlign.Center)
.padding({ left: 12, right: 12 })
.backgroundColor('#F1F3F5')
}
}
2.3、详情页界面设计
设计页面如下:

这里主要注意下3、4,因为很多组件都十分相似,我们可以进行复用从而降低代码量
官方解释:
区域3,知识地图详情页知识块:从设计图中可以观察到,这样的知识块可以不止一个,组件构造也都是一致,包含一个副标题和多行的知识点。因此可以将其封装成一个组件。
区域4,知识块内的每个知识点:左侧图标与右侧的右箭头图标可以采用Image组件实现,类型、标题可以用Text组件实现。
2.4、定义数据结构
这里不知道大家能否理解,其实第一次看见我真的一脸懵逼,仔细看了下发现并不难,我这里用简单的形式来讲解下数据是如何进行定义的。
interface KnowledgeBaseItem {
type: string,
title: string
}
interface Material {
subtitle: string,
knowledgeBase: KnowledgeBaseItem[]
}
export interface Section {
title: string,
brief: string,
materials: Material[]
}
大致就是这样子分类的,这里可以好好去理解下,我这里因为空间有限没有全部进行表明

开始准备本地的静态数据
@State section: Section = {
"title": "准备与学习",
"brief": "加入HarmonyOS生态,注册成为开发者,通过HarmonyOS课程了解基本概念和基础知识,轻松开启HarmonyOS的开发旅程。",
"materials": [
{
"subtitle": "HarmonyOS简介",
"knowledgeBase": [
{ "type": "准备", "title": "注册账号" },
{ "type": "准备", "title": "实名认证" },
{ "type": "学习与获取证书", "title": "HarmonyOS第一课" },
{ "type": "学习与获取证书", "title": "HarmonyOS应用开发者基础认证" }
]
},
{
"subtitle": "赋能套件介绍",
"knowledgeBase": [
{ "type": "指南", "title": "开发" },
{ "type": "指南", "title": "最佳实践" },
{ "type": "指南", "title": "API参考" },
{ "type": "指南", "title": "视频课程" },
{ "type": "指南", "title": "Codelabs" },
{ "type": "指南", "title": "FAQ" }
]
}
]
};
2.5、实现区域4
build内容如下,因为数据需要在父组件中获取,所以需要先进行引入

build() {
Scroll(this.scroller) {
Column() {
Text("准备与学习")
.fontFamily('HarmonyHeiTi-Bold')
.fontSize(20)
.fontWeight(700)
.fontColor(Color.Black)
Text(this.section?.brief)
.fontFamily('HarmonyHeiTi')
.fontSize(12)
.fontColor('rgba(0,0,0,0.60)')
.textAlign(TextAlign.JUSTIFY)
.fontWeight(400)
.margin({ top: 12 })
ForEach(this.section?.materials, (material: Material) => {
this.KnowledgeBlock(material)
}, (material: Material, index: number) => material.subtitle + index)
}
.alignItems(HorizontalAlign.Start)
.padding({top: 12, left: 16, bottom: 12, right: 16})
.backgroundColor('#F1F3F5')
.width('100%')
}
.align(Alignment.TopStart)
.constraintSize({ minHeight: '100%' })
.edgeEffect(EdgeEffect.Spring)
.scrollable(ScrollDirection.Vertical)
.scrollBar(BarState.Auto)
.backgroundColor('green')
不难看出这里很多组件都重复了,我们可以将它抽取出来,这里为了和官网保持一致,也选用@Builder来进行统一定义函数来完成

@Builder
KnowledgeBlockLine(knowledgeBaseItem: KnowledgeBaseItem) {
Row() {
Image($r(TypeMapIcon[knowledgeBaseItem.type]))
.width(20)
.height(20)
Column() {
Text(knowledgeBaseItem.title)
.fontFamily('HarmonyHeiTi-Medium')
.fontSize(16)
.fontWeight(500)
Text(knowledgeBaseItem.type)
.fontFamily('HarmonyHeiTi')
.fontSize(14)
.fontWeight(400)
}
.alignItems(HorizontalAlign.Start)
.margin({ left: 18 })
Blank()
Image($r('app.media.right'))
.width(12)
.height(24)
}
.width('100%')
.height(64)
.alignItems(VerticalAlign.Center)
}
这里的类型我们都提前定义好了,前面的图标是通过传入的string来对应的

这里大家可以进行自定义
const TypeMapIcon: Record<string, string> = {
'指南': 'app.media.logo',
'准备': 'app.media.logo2',
'学习与获取证书': 'app.media.logo',
'视频教程': 'app.media.logo2',
}
2.6、实现区域三

注意看这里也有重复的部分,所以我们也要将其抽象出来,这里还是用的@Builder
@Builder
KnowledgeBlock(material: Material) {
Column() {
Text(material.subtitle)
.fontFamily('HarmonyHeiTi-Medium')
.fontSize(14)
.fontWeight(500)
.margin({ bottom: 8 })
List({ space: 12 }) {
ForEach(material.knowledgeBase, (item: KnowledgeBaseItem, index: number) => {
ListItem(){
this.KnowledgeBlockLine(item)
}
}, (item: KnowledgeBaseItem, index: number) => item.title)
}
.backgroundColor(Color.White)
.borderRadius(16)
.padding({ left: 12, right: 12 })
.divider({
strokeWidth: 0.5,
startMargin: 38,
endMargin: 0,
color: '#F2F2F2'
})
}
.width('100%')
.margin({ top: 28 })
.alignItems(HorizontalAlign.Start)
}
这里为了方便大家观看我将这两个函数进行平行解释,就是通过函数调用的方式来进行循环渲染使得代码量大大减少

最后通过在build中调用KnowledgeBlock,注意下这里的Scroll,这里传入的参数应该是为了继承父组件的样式吧,这里我也不是很清楚,不传入参数应该也不会应影响正常运行
官方解释:
添加Scroll。Scroll内容可能会超过应用界面的长度,和之前在知识地图页的方案一样,采用Scroll组件包裹住外层,使得界面内容部分可以滑动展示。同时可以将之前加到外层Column容器上的背景色属性移动到Scroll上。
其中scrollable属性表示设置滚动方向,此处设置为ScrollDirection.Vertical表示允许纵向滚动。scrollBar属性表示以何种方式显示滚动条,支持一直显示、不显示以及滑动时显示,此处设为BarState.Auto表示滑动时显示。

2.7、改变数据获取方式
之前我们的数据是从json文件中进行获取的,现在我们需要改造一下,同样从接送文件中获取
这里不知道为什么和上次处理的模式不同了,可能是又多种方式吧

三、测试
全部完成后开始测试,这里的详情页不知道为什么无法展示,就是因为这里昨天硬控我一个小时也是没有解决,今天下午用官方给的文件也是这样,我一直以为是我的问题

知识地图页面测试成功,我这里的数据是自定义的

四、总结
相当于对单页面的能力进行了加强又熟悉了下整体的架构模式,下一节就要开启导航功能了,也就相当于路由功能,通过点击不同图标进行跳转页面。