HarmonyOS NEXT 应用开发实战(九、知乎日报项目详情页实现详细介绍)

news2024/11/26 10:33:55

在本篇博文中,我们将探讨如何使用 HarmonyOS Next 框架开发一个知乎日报的详情页,逐步介绍所用到的组件及代码实现。知乎日报是个小巧完整的小项目,这是一个循序渐进的过程,适合初学者和有一定开发经验的工程师参考。

1. 项目背景

知乎日报是一个非常热门的新闻聚合应用,通过API接口获取最新的新闻内容。在我们的实现中,我们将从知乎接口获取详情数据,并在应用中展示相应的内容。

1.1 知乎接口介绍

知乎日报提供了api接口,方便个人开发者联手使用。接口介绍:

### 获取最新日报
get https://news-at.zhihu.com/api/4/news/latest

###历史日报
get https://news-at.zhihu.com/api/4/news/before/20240617

### 热门日报
get http://news-at.zhihu.com/api/4/news/hot

### 主题日报
get http://news-at.zhihu.com/api/4/news/theme/2024
### 2016年
get http://news-at.zhihu.com/api/4/news/before/20240721

### 日报详情
get http://news-at.zhihu.com/api/4/news/9773253

 1.2日报详情页特殊处理

需要特别注意的是,知乎日报的详情页需要特殊处理,因为,因为后台返回的竟然是html.是的,你没听错,这有点儿。。。,但也不麻烦。我自己造了个后台接口特殊处理过了,处理为了这个样子:

2. 主要组件介绍

2.1 DetailPageBuilder

这是构建整个详情页的入口,是NavDestination组件包括着的一个子页面,它使用了HarmonyOS提供的Navigation组件路由,通过主页的点击进入详情页。

//zhihu.ets (主页)
build() {
    Navigation(this.pageStack){
        Column({ space: 0 }) {

          // 内容项
          Swiper(this.swiperController) {
            LazyForEach(this.swiperData, (item: ZhiNewsItem) => {
              Stack({ alignContent: Alignment.Center }) {
                Image(item.image)
                  .width('100%')
                  .height(200)
                  .backgroundColor(0xAFEEEE)
                  .zIndex(1)
                  .onClick(() => {
                    //this.pageStack.pushPathByName("PageOne", item)
                    //点击跳转到详情页
                    this.pageStack.pushDestinationByName("ZhiPageDetail", { id:item.id }).catch((e:Error)=>{
                      // 跳转失败,会返回错误码及错误信息
                      console.log(`catch exception: ${JSON.stringify(e)}`)
                    }).then(()=>{
                      // 跳转成功
                    });
                  })

                // 显示轮播图标题

2.2 DetailPage

该结构体是页面的核心包含所有的状态管理和生命周期回调。我们在其中定义了一些主要的状态变量,例如消息、页面数据和页面ID等。

2.3 生命周期回调

  • aboutToAppear: 组件即将出现时的处理逻辑,可以在这里做初始化操作。
  • aboutToDisappear: 组件即将消失时的处理逻辑,通常用于清理操作。

3. 代码实现

以下是主要代码部分:

import { getZhiHuDetail } from '../../../common/api/zhihu';
import { BaseResponse, ErrorResp, ZhiDetailRespData, ZhiDetailItem } from '../../../common/bean/ApiTypes';
import { Log } from '../../../utils/logutil';
import { LengthMetrics } from '@kit.ArkUI';

@Builder
export function DetailPageBuilder() {
  DetailPage();
}

@Component
struct DetailPage {
  @State message: string = 'Hello World';
  pageStack: NavPathStack = new NavPathStack();
  private pathInfo: NavPathInfo | null = null;
  @State detailData: ZhiDetailRespData | null = null;
  private pageId = '';

  // 组件生命周期
  aboutToAppear() {
    Log.info('Detail aboutToAppear');
  }

  // 组件生命周期
  aboutToDisappear() {
    Log.info('Detail aboutToDisappear');
  }

  build() {
    NavDestination() {
      Scroll() {
        Column({ space: 0 }) {
          Stack({ alignContent: Alignment.Bottom }) {
            Image(this.detailData?.image).width('100%').height(250).zIndex(1);
            
            // 显示轮播图标题
            Text(this.detailData?.title)
              .padding(5)
              .margin({ bottom: 10 })
              .width('100%')
              .height(50)
              .textAlign(TextAlign.Center)
              .maxLines(2)
              .textOverflow({ overflow: TextOverflow.Clip })
              .fontSize(16)
              .fontColor(Color.White)
              .opacity(100)
              .backgroundColor('#808080AA')
              .zIndex(2);
          }.height(250); // 设置高度

          Text(`${this.detailData?.author ?? ""} ${this.detailData?.bio ?? ""}`)
            .fontSize(14)
            .fontColor("#999")
            .padding(10).width('100%');

          Column() {
            ForEach(this.detailData?.content, (item: ZhiDetailItem, idx) => {
              if (item.types === 'p') {
                Text(item.value).fontSize(16).padding(10).lineSpacing(LengthMetrics.px(30)).width('100%').alignSelf(ItemAlign.Start);
              } else if (item.types === 'p.strong') {
                Text(item.value).fontSize(16).fontWeight(FontWeight.Bold).padding(10).width('100%').alignSelf(ItemAlign.Start);
              } else if (item.types === 'img') {
                Image(item.value).padding(10);
              }
            });
          }
        }
      }
    }
    .title("日报详情")
    .width('100%')
    .height('100%')
    .onReady(ctx => {
      this.pageStack = ctx.pathStack;
      this.pathInfo = ctx.pathInfo;

      interface params {
        id: string;
      }
      let par = ctx.pathInfo.param as params;
      Log.debug("par:%s", par.id);
      this.pageId = par.id;
      Log.info('current page config info is ' + JSON.stringify(ctx.getConfigInRouteMap()));
    })
    .onShown(() => {
      console.info('Detail onShown');
      getZhiHuDetail(this.pageId).then((res) => {
        Log.debug(res.data.message);
        Log.debug("request", "res.data.code:%{public}d", res.data.code);
        this.detailData = res.data;
      }).catch((err: BaseResponse<ErrorResp>) => {
        Log.debug("request", "err.data.code:%d", err.data.code);
        Log.debug("request", err.data.message);
      });
    });
  }
}

4. 代码解析

  • 数据获取:使用getZhiHuDetail(this.pageId)获取当前页面的内容,并将数据存储在detailData状态中。
  • 组件渲染:通过NavDestinationScroll组件容纳整个页面,确保内容在可滚动视图内。
  • 动态数据展示:使用${this.detailData?.author ?? ""} ${this.detailData?.bio ?? ""}实现了数据的安全合并,确保了在获取到的数据不存在时不发生错误。
  • 生命周期:在NavDestination的onReady事件里拿到上个页面传递的参数值,在onShown事件里完成数据请求,拿到详情数据。

5. 结论

通过本篇博文,我们对如何使用 HarmonyOS Next 开发知乎日报详情页进行了深入的探讨。这不仅涵盖了从API获取数据到页面渲染的整个流程,还详细介绍了相关组件的使用方法。在实践中,开发者可以根据具体需求进一步扩展和优化页面功能。

希望这篇博文对你理解 HarmonyOS Next 项目开发有所帮助!如果你有任何问题,欢迎在下方留言讨论。

项目开源地址

zhihudaily: HarmonyOS NEXT 项目开发实战,仿知乎日报的实现

写在最后

最后,推荐下笔者的业余开源app影视项目“爱影家”,推荐分享给与我一样喜欢免费观影的朋友。【注】:该项目仅限于学习研究使用!请勿用于其他用途!

开源地址:爱影家app开源项目介绍及源码

https://gitee.com/yyz116/imovie

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2236323.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LLM训练”中的“分布式训练并行技术;分布式训练并行技术

目录 “LLM训练”中的“分布式训练并行技术” 分布式训练并行技术 数据并行 流水线并行:按阶段(stage)进行切分 张量并行 序列并行 多维混合并行 自动并行 MOE并行 重要的分布式AI框架 “LLM训练”中的“分布式训练并行技术” 随着深度学习技术的不断发展,特别是…

论文阅读:Computational Long Exposure Mobile Photography (二)

这篇文章是谷歌发表在 2023 ACM transaction on Graphic 上的一篇文章&#xff0c;介绍如何在手机摄影中实现长曝光的一些拍摄效果。 Abstract 长曝光摄影能拍出令人惊叹的影像&#xff0c;用运动模糊来呈现场景中的移动元素。它通常有两种模式&#xff0c;分别产生前景模糊或…

测试概念以及测试bug

关于测试的概念 什么是需求&#xff1f; 需求分为用户需求和软件需求。 软件需求可以作为开发和测试工作的依据&#xff0c;而用户需求不一定是合理的&#xff0c;这里的不合理有很多的角度&#xff1a;技术角度上&#xff0c;市场需求上&#xff0c;投入成本和收益比噔噔。…

mac m1 docker本地部署canal 监听mysql的binglog日志

mac m1 docker本地部署canal监听mysql的binglog日志(虚拟机同理) 根据黑马视频部署 1.docker 部署mysql 1.docker拉取mysql 镜像 因为m1是arm架构.需要多加一条信息 正常拉取 docker pull mysql:tagm1拉取 5.7的版本. tag需要自己指定版本 docker pull --platform linux/x…

C++之旅——入门

Hello&#xff0c;各位小伙伴们&#xff0c;前几期我们学习了C语言和数据结构&#xff0c;有了一定的基础之后我们来挑战新的语言——C。 目录 一、初识C 1>C发展历史 2>C版本更新 3>C的热度 4>C的学习难度 5>C学习相关书籍 二、第一个C代码 三、C基础 …

Flutter中文字体设置指南:打造个性化的应用体验

在使用Flutter进行开发时&#xff0c;可能会遇到中文字体显示不正常或者字体不符合设计需求的情况。Flutter默认的中文字体往往无法满足某些用户对个性化和美观的需求。今天&#xff0c;我们就来详细探讨如何在Flutter应用中设置中文字体&#xff0c;并结合不同场景提供相应的解…

4.1 软件设计概要

软件设计概要 1、 软件设计的概念和设计质量1.1 软件设计基本任务1.2 设计模型1.3 软件设计特点1.4 设计质量属性1.5 设计指导原则 2、 设计相关八大概念抽象体系结构设计模式模块化信息隐藏功能独立精化重构 3、 四类设计技术概要3.1 数据设计3.2 体系架构设计体系结构组织和细…

MySQL表的增删改查(CRUD2)

美好的一天又开始了&#xff0c;大家今天有没有学习呢&#xff1f;没学的话&#xff0c;开始跟随和博主一起对MYSQL的学习吧&#xff01;&#xff01;&#xff01; 复习&#xff1a; CRUD新增1.新增 insert into 表名 [(列名[&#xff0c;列名,列名...])] values (值[,值,值.…

用接地气的例子趣谈 WWDC 24 全新的 Swift Testing 入门(三)

概述 从 WWDC 24 开始&#xff0c;苹果推出了全新的测试机制&#xff1a;Swift Testing。利用它我们可以大幅度简化之前“老态龙钟”的 XCTest 编码范式&#xff0c;并且使得单元测试更加灵动自由&#xff0c;更符合 Swift 语言的优雅品味。 在这里我们会和大家一起初涉并领略…

【案例】Excel使用宏来批量插入图片

一、场景介绍 我有一个excel文件&#xff0c;需要通过一列的文件名称&#xff0c;按照规则给批量上传图片附件。 原始文件&#xff1a; 成功后文件&#xff1a; 二、实现方法 1. 使用【wps】工具打开Excel文件&#xff0c;将其保存为启用宏的文件。 2.找到编辑宏的【VB编辑器…

Springboot项目报错记录

SpringBoot测试报错&#xff1a;Unable to find a SpringBootConfiguration, you need to use Context 该测试类所在测试包test下的包名和类路径java下的包名不一致导致的 引发以下报错 java.lang.IllegalStateException: Unable to find a SpringBootConfiguration, you need…

RabbitMQ 高级特性——消息分发

文章目录 前言消息分发RabbitMQ 分发机制的应用场景1. 限流2. 负载均衡 前言 当 RabbitMQ 的队列绑定了多个消费者的时候&#xff0c;队列会把消息分发给不同的消费者&#xff0c;每条消息只会发送给订阅列表的一个消费者&#xff0c;但是呢&#xff0c;RabbitMQ 默认是以轮询…

深度学习:bert模型

multi-headed机制 1、通过不同的head得到多个特征表达&#xff0c;一般8个head 2、将所有特征拼接在一起 3、降维&#xff0c;将Z0~Z7连接一个FC全连接实现降维 多层堆叠 位置编码 如何实现位置编码&#xff1f; &#xff08;1&#xff09;为每个时间步添加一个0-1范围内的数…

Vue实战学习(2)(Vue快速入门(快速构建一个局部Vue项目))

目录 一、Vue快速入门。 &#xff08;1&#xff09;快速入门的案例需求。 &#xff08;2&#xff09;原生js解决。 &#xff08;3&#xff09;使用Vue解决。 1、准备一个html页面。且该页面需要引入Vue模块。 2、创建Vue程序的应用实例。 3、准备html元素&#xff08;如div&…

SpringMVC学习记录(三)之响应数据

SpringMVC学习记录&#xff08;三&#xff09;之响应数据 一、页面跳转控制1、快速返回模板视图2、转发和重定向 二、返回JSON数据1、前置准备2、ResponseBody 三、返回静态资源1、静态资源概念2、访问静态资源 /*** TODO: 一个controller的方法是控制层的一个处理器,我们称为h…

Spring WebFlux 核心原理(2-3)

1、Project Reactor 高级 1.1、响应式流的生命周期 要理解多线程的工作原理以及 Reactor 中实现的各种内部优化&#xff0c;首先必须了解 Reactor 中响应式类型的生命周期。 1.1.1、组装时 流生命周期的第一部分是组装时&#xff08;assembly-time&#xff09;。 Reactor 提供…

Python爬虫与Web渗透测试入门指南——初学者防踩雷

目录 Python爬虫与Web渗透测试入门指南一、学习方向和基础知识Python爬虫学习方向Web渗透学习方向 二、具体知识点总结三、学习流程和典型案例案例1&#xff1a;Python爬虫 - 简单网页数据爬取案例2&#xff1a;Web渗透 - SQL注入漏洞检测与利用案例3&#xff1a;Python爬虫 - …

apache-seata-2.1.0 AT模式使用篇(配置简单)

最近在研究seata的AT模式&#xff0c;先在本地搭建了一个演示demo&#xff0c;看看seata是如何使用的。在网上搜的demo&#xff0c;配置相对来说都比较多。我最终搭建的版本&#xff0c;配置较少&#xff0c;所以写篇文章分享下&#xff0c;希望能帮到对seata感兴趣的小伙伴。先…

Java代码与数据库纽带——JDBC

ok&#xff0c;看了题目&#xff0c;就可以知道今天要分享的是JDBC 讲这个这之前&#xff0c;想讲讲之前的。 之前我们操作数据库基本都是通过MySQL客户端&#xff0c;进行编写sql语句来操作的。 但是我们在开发中一般都是通过代码来操控数据库的。 而且在我们日常开发中&a…

navicat pg库安装mysql fdw 外表扩展

在Windows上手动安装mysql_fdw&#xff08;MySQL Foreign Data Wrapper&#xff09;通常涉及一系列步骤&#xff0c;包括下载源码、编译、配置和测试。以下是一个详细的指南&#xff1a; 一、下载mysql_fdw源码 访问mysql_fdw的GitHub发布页面&#xff0c;选择最新版本的源码…