HarmonyOS-鸿蒙金砖赛

170 阅读8分钟

帝心:全网首发HarmonyOS4.0教程(哔哩哔哩)创作者。致力于推广鸿蒙教程开发。

  1. 个人网站-鸿蒙学院
  2. 语雀笔记-编程视界
  3. 微信公众号:不多讲故事

前置知识

1. 类和对象

定义书籍类。由如下属性:

  1. 书籍编号标识:id
  2. 书名:bookName
  3. 作者:author
  4. 描述:summary
  5. 封面图片:coverImg
  6. 书籍介绍视频:video

a. 书籍类

class Book {
  id: string = '000'
  bookName: string = '帝心的书'
  author: string = '帝心'
  summary: string = '南州知我意,吹梦到西洲'
  coverImg: string = '/images/defaultLibrary.png'
  video: string = '/video/dxinVideo1.mp4'

  constructor(id: string, bookName: string, author: string, summary: string, coverImg: string, video: string) {
    this.id = id
    this.bookName = bookName
    this.author = author
    this.summary = summary
    this.coverImg = coverImg
    this.video = video
  }
}

以上定义方式,所有参数为必传参数。即,创建对象时,需要按照顺序逐个传入属性值。

b. 创建对象

new Book('001','红楼','雪芹','真作假时假亦真 无为有处有还无','/image/honglou.png','/video/dxinVideo1.mp4')

c. 参数省略

创建类时给定了默认属性值。如果创建对象时不想传递参数。则可以免写指定参数。

注意:

  1. 部分参数省略时,要放在构造函数参数列表的最后部分。
  2. 本示例演示全部可省参数
class Book {
  id?: string = '000'
  bookName?: string = '帝心的书'
  author?: string = '帝心'
  summary?: string = '南州知我意,吹梦到西洲'
  coverImg?: string = '/images/defaultLibrary.png'
  video?: string = '/video/dxinVideo1.mp4'

  constructor(id?: string, bookName?: string, author?: string, summary?: string, coverImg?: string, video?: string) {
    this.id = id
    this.bookName = bookName
    this.author = author
    this.summary = summary
    this.coverImg = coverImg
    this.video = video
  }
}

d. 创建对象

new Book()
new Book('001', '红楼', '雪芹', '真作假时假亦真 无为有处有还无', '/image/honglou.png', '/video/dxinVideo1.mp4')
new Book('001', '红楼', '雪芹', '真作假时假亦真 无为有处有还无')

e. 简写形式

如果一个类属性过多,需要在类中书写多行属性声明,且在构造函数中挨个赋值。代码臃肿。可简化书写形式。

纯血鸿蒙中:不支持在constructor中声明字段

class Book {
  constructor(
    public id?: string, 
    public bookName?: string, 
    public author?: string, 
    public summary?: string, 
    public coverImg?: string, 
    public video?: string
  ) {  }
}

2. HTTP交互和云

a. 注册登录华为云官方网站

b. 创建华为云函数

华为云首页搜索云函数工作流参考文档进行学习使用


3. JSON文件读取和解析

JSON文件作为一种轻量级的文本格式,用于表示结构化数据。JSON 文件通常以 .json 作为文件扩展名,例如 data.json

JSON 文件常用于以下场景:

  • 配置文件: 存储应用程序或系统的配置信息。
  • 数据交换: 在不同系统之间传递数据,例如 Web 服务返回的数据。
  • 数据存储: 保存或导出数据,例如日志文件、用户设置、游戏数据等。
基本结构:

一个 JSON 文件通常由一个 JSON 对象或一个 JSON 数组组成。JSON 对象是一组无序的键值对,而 JSON 数组是一组有序的值。以下是 JSON 文件的两个基本结构:

JSON 允许在对象中嵌套对象,也允许在数组中嵌套数组或对象。

JSON 支持以下数据类型:

  • 字符串(String): 使用双引号括起来的文本。
  • 数字(Number): 整数或浮点数。
  • 布尔值(Boolean): truefalse
  • 数组(Array): 有序的值的列表。
  • 对象(Object): 无序的键值对集合。
  • null: 表示空值。

JSON文件中不允许写注释

[
  {
    "id": "0",
    "bookName": "南风意",
    "author": "帝心",
    "summary": "南风知我意,吹梦到西州",
    "coverImg": "/images/dixin.jpg",
    "video": "/video/dxinVideo1.mp4"
  },
  {
    "id": "1",
    "bookName": "红楼梦",
    "author": "曹雪芹",
    "summary": "《红楼梦》,中国古代章回体长篇小说,中国古典四大名著之一。其通行本共120回,一般认为前80回是清代作家曹雪芹所著,后40回作者为无名氏,整理者为程伟元、高鹗。小说以贾、史、王、薛四大家族的兴衰为背景,以富贵公子贾宝玉为视角,以贾宝玉与林黛玉、薛宝钗的爱情婚姻悲剧为主线,描绘了一些闺阁佳人的人生百态,展现了真正的人性美和悲剧美,是一部从各个角度展现女性美以及中国古代社会百态的史诗性著作。",
    "coverImg": "/images/honglou.jpg",
    "video": "/video/dxinVideo1.mp4"
  },
  {
    "id": "2",
    "bookName": "西游记",
    "author": "施耐庵",
    "summary": "该小说主要讲述了孙悟空出世,跟随菩提祖师学艺及大闹天宫后,遇见了唐僧、猪八戒、沙僧和白龙马,西行取经,一路上历经艰险,降妖除魔,经历了九九八十一难,终于到达西天见到如来佛祖,最终五圣成真的故事。该小说以“玄奘取经”这一历史事件为蓝本,经作者的艺术加工,深刻地描绘出明朝时期的社会生活状况。",
    "coverImg": "/images/xiyou.jpg",
    "video": "/video/dxinVideo2.mp4"
  },
  {
    "id": "3",
    "bookName": "三国演义",
    "author": "罗贯中",
    "summary": "哥们躬耕于南阳,瘪三往返三趟,问其天下事,满朝文武吱吱呜呜,吾仰天长啸:自董卓睡貂蝉以来,天下豪杰并起,跨洲连郡者不可胜数,唯吕布恨我最甚",
    "coverImg": "/images/sanguo.jpg",
    "video": "/video/dxinVideo1.mp4"
  },
  {
    "id": "4",
    "bookName": "水浒传",
    "author": "帝心",
    "summary": "唐僧路过贾府跟黛玉化缘,黛玉相中活泼悟空,遂结良缘。悟空书上偷桃,黛玉树下脏话,鲁智深看不下去,一把把树拔了起来",
    "coverImg": "/images/shuihu.jpg",
    "video": "/video/dxinVideo2.mp4"
  },
  {
    "id": "5",
    "bookName": "金瓶梅",
    "author": "泽宇",
    "summary": "泽宇哥哥与邻家官人日がたつにつれて情がわく",
    "coverImg": "/images/jinpingmei.jpg",
    "video": "/video/dxinVideo1.mp4"
  }
]
{
  "books":[
  {
    "id": "0",
    "bookName": "南风意",
    "author": "帝心",
    "summary": "南风知我意,吹梦到西州",
    "coverImg": "/images/dixin.jpg",
    "video": "/video/dxinVideo1.mp4"
  },
  {
    "id": "1",
    "bookName": "红楼梦",
    "author": "曹雪芹",
    "summary": "《红楼梦》,中国古代章回体长篇小说,中国古典四大名著之一。其通行本共120回,一般认为前80回是清代作家曹雪芹所著,后40回作者为无名氏,整理者为程伟元、高鹗。小说以贾、史、王、薛四大家族的兴衰为背景,以富贵公子贾宝玉为视角,以贾宝玉与林黛玉、薛宝钗的爱情婚姻悲剧为主线,描绘了一些闺阁佳人的人生百态,展现了真正的人性美和悲剧美,是一部从各个角度展现女性美以及中国古代社会百态的史诗性著作。",
    "coverImg": "/images/honglou.jpg",
    "video": "/video/dxinVideo1.mp4"
  },
  {
    "id": "2",
    "bookName": "西游记",
    "author": "施耐庵",
    "summary": "该小说主要讲述了孙悟空出世,跟随菩提祖师学艺及大闹天宫后,遇见了唐僧、猪八戒、沙僧和白龙马,西行取经,一路上历经艰险,降妖除魔,经历了九九八十一难,终于到达西天见到如来佛祖,最终五圣成真的故事。该小说以“玄奘取经”这一历史事件为蓝本,经作者的艺术加工,深刻地描绘出明朝时期的社会生活状况。",
    "coverImg": "/images/xiyou.jpg",
    "video": "/video/dxinVideo2.mp4"
  },
  {
    "id": "3",
    "bookName": "三国演义",
    "author": "罗贯中",
    "summary": "哥们躬耕于南阳,瘪三往返三趟,问其天下事,满朝文武吱吱呜呜,吾仰天长啸:自董卓睡貂蝉以来,天下豪杰并起,跨洲连郡者不可胜数,唯吕布恨我最甚",
    "coverImg": "/images/sanguo.jpg",
    "video": "/video/dxinVideo1.mp4"
  },
  {
    "id": "4",
    "bookName": "水浒传",
    "author": "帝心",
    "summary": "唐僧路过贾府跟黛玉化缘,黛玉相中活泼悟空,遂结良缘。悟空书上偷桃,黛玉树下脏话,鲁智深看不下去,一把把树拔了起来",
    "coverImg": "/images/shuihu.jpg",
    "video": "/video/dxinVideo2.mp4"
  },
  {
    "id": "5",
    "bookName": "金瓶梅",
    "author": "泽宇",
    "summary": "泽宇哥哥与邻家官人日がたつにつれて情がわく",
    "coverImg": "/images/jinpingmei.jpg",
    "video": "/video/dxinVideo1.mp4"
  }
]
}

a. 读取JSON文件

导入即对象

import book from 'resources/rawfile/book.json'
import book from 'resources/rawfile/book.json'
import Book from '../model/Book'

@Entry
@Component
struct ReadJSON {
  build() {
    Column({ space: 30 }) {
      Text('读取JSON并解析数据到Book类型').fontSize(30)
      List({ space: 20 }) {
        ForEach(book, (bookItem: Book) => {
          ListItem() {
            Row() {
              Image(bookItem.coverImg).width(100)
              Column() {
                Text(bookItem.bookName).fontSize(22)
                Text(bookItem.author).fontColor('#ffd43020')
                Text(bookItem.summary)
                  // .maxLines(2)
                  // .textOverflow({ overflow: TextOverflow.Ellipsis })
                  .textOverflow({ overflow: TextOverflow.MARQUEE })
              }
              .width('60%')
              .height('100%')
              .justifyContent(FlexAlign.SpaceAround)
            }
            .width('90%')
            .height(150)
            .justifyContent(FlexAlign.SpaceAround)
          }
        })
      }
      .width('100%')
      .layoutWeight(1)
    }
    .width('100%')
    .height('100%')
    .backgroundColor($r('app.color.theme_color'))
  }
}

应用开发-UI

1. 设计首页并跳转

业务逻辑

  1. 首页加载即从华为云函数工作流获取图书馆名称

    1. 需要先申请网络权限
  2. 点击logo图标跳转到图书馆主页

细节

  1. 华为云函数工作流的API应抽取到src/main/ets/common/Constants.ets中,方便维护。
  2. 页面跳转前应提前准备好目标页,以方便使用其路由地址。
  3. 路由跳转,获取参数对象时要求结果是名确的对象类型。所以需要提前设计参数的对象模型
 "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ]
//  使用路由获取参数  要求获取的结果是一个对象类型
// Index页面传递参数 Library 传递的是一个字符串类型
// Library 页面传递参数 BookDetail  传递一个Book对象

import Book from './Book'
export default  class RouterParam{
  paramKey:string | Book = ''
}
import { http } from '@kit.NetworkKit';
import Constants from '../common/Constants';
import { router } from '@kit.ArkUI';
import IndexToLibraryParam from '../model/RouterParam';

@Entry
@Component
struct Index {
  @State libraryName: string = '从华为云获取';

  async aboutToAppear(): Promise<void> {
    let data = await http.createHttp().request(Constants.getLibraryName)
    this.libraryName = data.result as string
  }
  build() {
    Column({ space: 30 }) {
      Image($r('app.media.logo'))
        .width(200)
        .onClick(() => {
          router.pushUrl({
            url: "pages/Library",
            params:{
              paramKey:this.libraryName
            }
          })
        })
      Text(this.libraryName)
        .fontSize(30)
        .fontColor($r('app.color.titile_color'))
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .backgroundColor($r('app.color.theme_color'))

  }
}

2. 图书馆主页

  1. 图书馆名称:从首页传递过来的参数中解析
  2. 图书馆描述:从华为云函数获取

> 前文创建过响应图书馆名称的函数,可以继续创建更多函数。

  1. 图书列表:读取book.json文件并渲染UI
import Book from '../model/Book'
import book from 'resources/rawfile/book.json'
import router from '@ohos.router'
import RouterParam from '../model/RouterParam'
import { http } from '@kit.NetworkKit'
import Constants from '../common/Constants'

@Entry
@Component
struct Library {
  //路由参数对象
  paramObj: RouterParam = router.getParams() as RouterParam
  // 图书馆名称
  libraryName: string = this.paramObj?.paramKey as string || 'libraryName'
  // 图书馆描述  来源于华为云函数
  @State libraryDescription: string = '描述'

  async aboutToAppear(): Promise<void> {
    // 访问华为云获取 图书馆描述
    let data = await http.createHttp().request(Constants.getLibraryDesc)

    this.libraryDescription = data.result as string
    console.log(this.libraryDescription)
  }

  build() {
    Column({ space: 30 }) {
      Text(this.libraryName)
        .fontSize(30)
        .fontColor($r('app.color.titile_color'))

      Text(this.libraryDescription)
        .fontSize(20)
        .fontColor('#ff83802a')
      List({ space: 20 }) {
        ForEach(book, (bookItem: Book) => {
          ListItem() {
            Row() {
              Image(bookItem.coverImg).width(100)
              Column() {
                Text(bookItem.bookName).fontSize(22)
                Text(bookItem.author).fontColor('#ffd43020')
                Text(bookItem.summary)// .maxLines(2)
                  // .textOverflow({ overflow: TextOverflow.Ellipsis })
                  .textOverflow({ overflow: TextOverflow.MARQUEE })
              }
              .width('60%')
              .height('100%')
              .justifyContent(FlexAlign.SpaceAround)
            }
            .width('90%')
            .height(150)
            .justifyContent(FlexAlign.SpaceAround)
          }
          .width('90%')
          .borderRadius(10)
          .backgroundColor('#fff1c2e0')
          .onClick(() => {
            // 跳转到书籍详情页
            router.pushUrl({
              url: "pages/BookDetail",
              params: {
                paramKey:bookItem
              }
            })
          })
        })
      }
      .width('100%')
      .alignListItem(ListItemAlign.Center)
      .layoutWeight(1)
    }
    .width('100%')
    .height('100%')
    .backgroundColor($r('app.color.theme_color'))
  }
}

3. 书籍详情页

  1. 顶部:返回按钮+当前图书名
  2. 主体:书籍图片+作者+书籍描述+书籍视频
// 书籍详情页
import Book from '../model/Book'
import { router } from '@kit.ArkUI'
import RouterParam from '../model/RouterParam'

@Entry
@Component
struct BookDetail {
  book: Book =
    (router.getParams() as RouterParam)?.paramKey as Book || new Book("000", "书名", "作者", "描述", "封面", "视频")

  //视频控制器
  videoController:VideoController = new VideoController()
  build() {
    Column({ space: 30 }) {
      // 顶部返回按钮 + 图书名
      Row() {
        Image($r('app.media.ic_public_back'))
          .width(40)
          .onClick(() => {
            router.back()
          })
        Text(this.book.bookName)
          .font({
            size: 40, weight: 700, style: FontStyle.Italic
          })
          .fontColor('#ffc627a4')
      }
      .width('100%')
      .height(60)
      .justifyContent(FlexAlign.SpaceAround)

      // 书籍图片 + 作者 + 书籍描述 + 视频
      Image(this.book.coverImg)
        .width('30%')
      List() {
        ListItem() {
          Column({ space: 30 }) {
            Text(this.book.author)
              .font({ size: 30 })
              .fontColor('#ff1813b5')
            Text(this.book.summary)
              .font({ size: 20 })
              .fontColor('#ff0b566d')

            Video({ src: this.book.video, controller: this.videoController})
              .width('80%')
              .height('50%')
              .autoPlay(false)
              .controls(true)
              .loop(false)
          }
        }
      }
      .width('100%')
      .layoutWeight(1)
      .backgroundColor('#eee')
    }
    .width('100%')
    .height('100%')
    .backgroundColor($r('app.color.theme_color'))
  }
}

4. 运行效果

1727334968838-f15dab1c-4d26-41a9-a9ed-bfc3fd0f6488.gif


电话服务

电话服务仅需一行代码即可实现。自行设计UI效果,绑定点击事件。

Text(){
  Span('图书馆电话')
  Span('15890100305')
    .fontColor('#ff0fa3e7')
    .fontSize(20)
    .onClick(() => {
      //电话服务功能实现 :点击电话号码可以跳转到拨打电话界面
      call.makeCall("15890100305")
    })
}

公共事件与通知功能实现


数据管理


窗口管理


web交互