关联章节
- HarmonyOS第一课05:案例
- HarmonyOS第一课05:应用架构设计基础——MVVM模式
- HarmonyOS第一课05:应用架构设计基础——三层架构
- HarmonyOS第一课06:ArkWeb页面适配
- HarmonyOS第一课06:通过结构化数据构建页面
说明:本章代码基于HarmonyOS第一课06:通过结构化数据构建页面代码
页面效果
文件变动
代码
default
pages/Index.ets
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | import { QuickStartPage } from '@ohos/quickstart' import { CourseLearning } from '@ohos/learning' import { KnowledgeMap } from '@ohos/map' @Entry @Component struct Index {   @State currentIndex: number = 0   private tabsController: TabsController = new TabsController()   @Builder   tabBarBuilder(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.6)')         .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')))     }     .scrollable(false)     .vertical(false)     .divider({       strokeWidth: 0.5,       color: '#0D182431'     })     .backgroundColor('#F1F3F5')     .padding({ top: 36, bottom: 28 })   } } | 
map
pages/KnowledgeMap.ets
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | import { NavBarItemType, NavBarItem } from '../view/NavBarItem' import { KnowledgeMapContent, Section } from '../view/KnowledgeMapContent' import { BusinessError } from '@kit.BasicServicesKit' import { util } from '@kit.ArkTS' @Component export struct KnowledgeMap {   @State navBarList: NavBarItemType[] = [     { order: '01', title: '准备与学习' },     { order: '02', title: '构建应用' },     { order: '03', title: '应用测试' },     { order: '04', title: '上架' },     { order: '05', title: '运营增长' },     { order: '06', title: '商业变现' },     { order: '07', title: '更多' }   ]   @State sections: Section[] = []   @Provide('knowledgeMapPageStack') knowledgeMapPageStack: NavPathStack = new NavPathStack()   @State currentNavBarIndex: number = -1   @Builder   PageMap(name: string) {     if (name === 'KnowledgeMapContent') {       KnowledgeMapContent({ section: this.sections[this.currentNavBarIndex] })     }   }   private getSections() {     try {       getContext(this).resourceManager.getRawFileContent("MapData.json", (error: BusinessError, value: Uint8Array) => {         const textDecoder = util.TextDecoder.create('utf-8')         const res = textDecoder.decodeWithStream(value, {           stream: false         })         this.sections = JSON.parse(res)       })     } catch (error) {       console.error(`callback getRawFileContent failed, error is ${JSON.stringify(error)}`)     }   }   aboutToAppear(): void {     this.getSections()   }   build() {     Navigation(this.knowledgeMapPageStack) {       Scroll() {         Column() {           Text('知识地图')             .fontFamily('HarmonyHeiTi-Bold')             .fontSize(24)             .fontColor(Color.Black)             .textAlign(TextAlign.Start)             .lineHeight(33)             .fontWeight(700)             .width('100%')           Image($r('app.media.knowledge_map_banner'))             .width('100%')             .borderRadius(16)             .margin({ top: 19, bottom: 8 })           Text('通过循序渐进的学习路径,无经验和有经验的开发者都可以轻松掌握ArkTS语言声明式开发范式,体验更简洁、更友好的HarmonyOS应用开发旅程。')             .fontFamily('HarmonyHeiti')             .fontSize(14)             .fontColor('rgba(0, 0, 0, 0.6)')             .fontWeight(400)             .textAlign(TextAlign.Start)           List({ space: 12 }) {             ForEach(this.navBarList, (item: NavBarItemType, index: number) => {               ListItem() {                 NavBarItem({ navBarItem: item, currentNavBarIndex: this.currentNavBarIndex })               }               .width('100%')             }, (item: NavBarItemType): string => item.title)           }           .width('100%')           .margin({ top: 24 })         }         .padding({           top: 12,           right: 16,           bottom: 12,           left: 16         })         .backgroundColor("#F1F3F5")       }       .backgroundColor('#F1F3F5')       .align(Alignment.TopStart)       .constraintSize({ minHeight: '100%' })       .edgeEffect(EdgeEffect.Spring)     }     .hideTitleBar(true)     .navDestination(this.PageMap)     .mode(NavigationMode.Stack)   } } | 
view/KnowledgeMapContent.ets
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | interface KnowledgeBaseItem {   type: string,   title: string } interface Material {   subtitle: string,   knowledgeBase: KnowledgeBaseItem[] } export interface Section {   title: string,   brief: string,   materials: Material[] } const TypeMapIcon: Record<string, string> = {   '指南': 'app.media.ic_guide',   '准备': 'app.media.ic_prepare',   '学习与获取证书': 'app.media.ic_medals',   '视频教程': 'app.media.ic_video' } @Component export struct KnowledgeMapContent {   @Prop section: Section   @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.ic_arrow'))         .width(12)         .height(24)     }     .width('100%')     .height(64)     .alignItems(VerticalAlign.Center)   }   @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() {     NavDestination() {       Scroll() {         Column() {           Text(this.section.title)             .fontFamily('HarmonyHeiTi-Bold')             .fontSize(20)             .fontWeight(700)             .fontColor(Color.Black)           Text(this.section.brief)             .fontFamily('HarmonyHeiTi')             .fontSize(12)             .fontColor('rgba(0, 0, 0, 0.6)')             .textAlign(TextAlign.JUSTIFY)             .fontWeight(400)             .margin({ top: 12 })           ForEach(this.section.materials, (material: Material) => {             this.KnowledgeBlock(material)           }, (material: Material, index: number) => material.subtitle)         }         .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('#F1F3F5')     }     .hideTitleBar(true)   } } | 
view/NavBarItem.ets
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | export interface NavBarItemType {   order: string   title: string } @Component export struct NavBarItem {   @Prop navBarItem: NavBarItemType   @Consume('knowledgeMapPageStack') knowledgeMapPageStack: NavPathStack   @Link currentNavBarIndex: number   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')         .lineHeight(22)         .fontWeight(500)       Blank()       Image($r('app.media.ic_arrow'))         .width(12)         .height(24)     }     .width('100%')     .height(48)     .borderRadius(16)     .alignItems(VerticalAlign.Center)     .padding({ left: 12, right: 12 })     .backgroundColor(       this.currentNavBarIndex === Number(this.navBarItem.order) - 1 ?         '#1A0A59F7' :       Color.Transparent     )     .onClick(() => {       const index = Number(this.navBarItem.order) - 1       this.currentNavBarIndex = index       this.knowledgeMapPageStack.replacePath({ name: 'KnowledgeMapContent' })     })   } } | 
quickstart
pages/QuickStartPage.ets
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | import { TutorialView } from '../view/TutorialView' import { Banner } from '../view/Banner' import { EnablementView } from '../view/EnablementView' import { ArticleClass } from '../model/ArticleClass' import { BannerClass } from '../model/BannerClass' import { ArticleDetailPage } from './ArticleDetailPage' import { BannerDetailPage } from './BannerDetailPage' @Component export struct QuickStartPage {   @State message: string = '快速入门'   @Provide('articlePathStack') articlePathStack: NavPathStack = new NavPathStack()   @Builder   quickStartRouter(name: string, param?: ArticleClass | BannerClass) {     if (name === 'articleDetail') {       ArticleDetailPage()     } else if (name === 'bannerDetailPage') {       BannerDetailPage()     }   }   build() {     Navigation(this.articlePathStack) {       Column() {         Text(this.message)           .fontFamily('HarmonyHeiTi-Bold')           .fontSize(24)           .fontWeight(700)           .lineHeight(33)           .width('100%')           .textAlign(TextAlign.Start)           .margin({ left: 16 })         Scroll() {           Column() {             Banner()             EnablementView()             TutorialView()           }         }         .layoutWeight(1)         .scrollBar(BarState.Off)         .align(Alignment.TopStart)       }       .height('100%')       .width('100%')       .backgroundColor('#F1F3F5')     }     .navDestination(this.quickStartRouter)     .hideTitleBar(true)     .mode(NavigationMode.Stack)   } } | 
pages/ArticleDetailPage.ets
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | import { ArticleClass } from '../model/ArticleClass' import { webview } from '@kit.ArkWeb' @Preview @Component export struct ArticleDetailPage {   @State articleDetail: ArticleClass | null = null   @Consume('articlePathStack') articlePathStack: NavPathStack   aboutToAppear(): void {     this.articleDetail = this.articlePathStack.getParamByName('articleDetail')[0] as ArticleClass   }   build() {     NavDestination() {       Column() {         Row() {           Row() {             Image($r('app.media.ic_back'))               .width(40)               .height(40)               .onClick(() => {                 this.articlePathStack.pop()               })             Row() {               Text(this.articleDetail?.title)                 .fontFamily('HarmonyHeiTi-Bold')                 .fontSize(20)                 .textAlign(TextAlign.Center)                 .textOverflow({ overflow: TextOverflow.Ellipsis })                 .maxLines(1)                 .fontWeight(700)                 .margin({ left: 8 })             }           }           .width('80%')         }         .justifyContent(FlexAlign.SpaceBetween)         .width('100%')         .height(56)         WebComponent({ articleDetail: this.articleDetail })       }       .padding({ left: 16, right: 16 })       .width('100%')       .width('100%')       .height('100%')       .justifyContent(FlexAlign.SpaceBetween)     }     .hideTitleBar(true)   } } @Component struct WebComponent {   @Prop articleDetail: ArticleClass | null   private webviewController: webview.WebviewController = new webview.WebviewController()   build() {     Column() {       Web({ src: this.articleDetail?.webUrl, controller: this.webviewController })         .darkMode(WebDarkMode.Auto)         .domStorageAccess(true)         .zoomAccess(true)         .fileAccess(true)         .mixedMode(MixedMode.All)         .cacheMode(CacheMode.None)         .javaScriptAccess(true)         .width('100%')         .layoutWeight(1)     }   } } | 
pages/BannerDetailPage.ets
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | import { BannerClass } from '../model/BannerClass' import { webview } from '@kit.ArkWeb' @Component export struct BannerDetailPage {   @State bannerClass: BannerClass | null = null   controller: webview.WebviewController = new webview.WebviewController()   @Consume('articlePathStack') articlePathStack: NavPathStack   aboutToAppear(): void {     this.bannerClass = this.articlePathStack.getParamByName('bannerDetailPage')[0] as BannerClass   }   build() {     NavDestination() {       Column() {         Web({           src: this.bannerClass?.url,           controller: this.controller         })           .darkMode(WebDarkMode.Auto)           .domStorageAccess(true)           .zoomAccess(true)           .fileAccess(true)           .mixedMode(MixedMode.All)           .javaScriptAccess(true)           .width('100%')           .layoutWeight(1)       }     }     .width('100%')     .height('100%')   } } | 
view/Banner.ets
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | import { BannerClass } from '../model/BannerClass' import { bufferToString } from '../util/BufferUtil' @Preview @Component export struct Banner {   @State bannerList: BannerClass[] = []   @Consume('articlePathStack') articlePathStack: NavPathStack   getBannerDataFromJSON() {     getContext(this).resourceManager.getRawFileContent('BannerData.json').then(value => {       // 获取buffer内容       // let buffer: ArrayBufferLike = value.buffer       // 转换为字符串       // let res: string = bufferToString(buffer)       // 解析为数据结构       // this.bannerList = JSON.parse(res) as BannerClass[]       // 简写       this.bannerList = JSON.parse(bufferToString(value.buffer)) as BannerClass[]     })   }   aboutToAppear(): void {     this.getBannerDataFromJSON()   }   build() {     Swiper() {       ForEach(this.bannerList, (item: BannerClass, index: number) => {         Image($r(item.imageSrc))           .objectFit(ImageFit.Contain)           .width('100%')           .padding({ top: 11, left: 16, right: 16 })           .borderRadius(16)           .onClick(() => {             this.articlePathStack.pushPathByName('bannerDetailPage', item)           })       }, (item: BannerClass, index: number) => item.id)     }     .autoPlay(true)     .loop(true)     .indicator(       new DotIndicator()         .color('#1a000000')         .selectedColor('#0A59F7')     )   } } | 
view/EnablementView.ets
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | 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(160)     .height(169)     .borderRadius(16)     .backgroundColor(Color.White)   } } @Preview @Component export struct EnablementView {   @State enablementList: Array<ArticleClass> = []   @Consume('articlePathStack') articlePathStack: NavPathStack   aboutToAppear(): void {     this.getEnablementDataFromJSON()   }   getEnablementDataFromJSON() {     getContext(this).resourceManager.getRawFileContent('EnablementData.json').then(value => {       this.enablementList = JSON.parse(bufferToString(value.buffer)) as ArticleClass[]     })   }   build() {     Column() {       Text('赋能套件')         .width('100%')         .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 })               .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 })     }     .width('100%')     .margin({ top: 18 })   } } | 
view/TutorialView.ets
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | 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))         .height(64)         .width(108)         .objectFit(ImageFit.Cover)         .borderRadius(16)     }     .width('100%')     .height(88)     .borderRadius(16)     .backgroundColor(Color.White)     .padding(12)     .alignItems(VerticalAlign.Top)   } } @Preview @Component export struct TutorialView {   @State tutorialList: Array<ArticleClass> = []   @Consume('articlePathStack') articlePathStack: NavPathStack   aboutToAppear(): void {     this.getTutorialDataFromJSON()   }   getTutorialDataFromJSON() {     getContext(this).resourceManager.getRawFileContent('TutorialData.json').then(value => {       this.tutorialList = JSON.parse(bufferToString(value.buffer)) 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 })               .onClick(() => {                 this.articlePathStack.pushPathByName('articleDetail', item)               })           }         }, (item: ArticleClass) => item.id)       }       .scrollBar(BarState.Off)       .padding({ left: 16, right: 16 })     }     .width('100%')     .margin({ top: 18 })     .alignItems(HorizontalAlign.Start)   } } | 
下载源码
官网地址
https://developer.huawei.com/consumer/cn/training/course/slightMooc/C101717497640610394


 
				