当前位置: 首页 > article >正文

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

在本篇博文中,我们将探讨如何使用 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.kler.cn/a/384463.html

相关文章:

  • C++ 并发专题 - 条件变量的使用
  • 实现 Nuxt3 预览PDF文件
  • FFmpeg 4.3 音视频-多路H265监控录放C++开发十. 多线程控制帧率。循环播放,QT connect 细节,
  • 本地Docker部署ZFile网盘打造个人云存储,告别公共网盘让你数据安全感爆棚
  • sql报错信息将字符串转换为 uniqueidentifier 时失败
  • C6.【C++ Cont】cout的格式输出
  • 【MATLAB源码-第210期】基于matlab的OFDM电力线系统仿真,不同梳状导频间隔对比。三种信道估计,三种插值误码率对比
  • 市场营销应该怎么学?
  • SW - 将step中的输入实体转成零件
  • wpf 制作丝滑Flyout浮出侧边栏Demo (Mahapps UI框架)
  • Springboot 整合 Java DL4J 打造自然语言处理之语音识别系统
  • TypeScript完整学习 --【比降价金还值!】
  • 计算机毕业设计Python+图神经网络手机推荐系统 手机价格预测 手机可视化 手机数据分析 手机爬虫 Django Flask Spark 知识图谱
  • vue3 ref对象的width改变了,并不会直接去更新视图,但是触发obj.width++是可以正常更新视图的简单处理方法
  • springBoot动态加载jar,将类注册到IOC
  • MongoDB笔记01-概念与安装
  • <网络> 协议
  • go 集成viper 配置管理
  • 简易抽奖器源码以及打包操作
  • 【网络-交换机】生成树协议、环路检测
  • Java 8 Stream API 详解
  • 实时金融股票数据API接口websocket接入方法
  • WRF-LES与PALM模型:风能资源评估、风力发电、大涡模拟、大尺度湍流涡旋、大雾预报、局地环流模拟、城市热岛效应、流场模拟
  • 香港服务器怎么搭建docker加速器
  • flutter 项目初建碰到的控制台报错无法启动问题
  • 地理空间-Java实现航迹稀释