HarmonyOS NEXT应用开发边学边玩系列:从零实现一影视APP (三、影视搜索页功能实现)

devtools/2025/1/19 4:47:07/

在HarmonyOS NEXT开发环境中,可以使用@nutpi/axios库来简化网络请求的操作。本文将展示如何使用HarmonyOS NEXT框架和@nutpi/axios库,从零开始实现一个简单的影视APP,主要关注影视搜索页的功能实现。

为什么选择@nutpi/axios

nutpi/axios是坚果派出品的,对axios封装过的鸿蒙HTTP客户端库,用于简化axios库的使用和以最简单的形式写代码。使用nutpi/axios库可以大大简化代码,使网络接口变得简单直观。

项目开源地址:https://atomgit.com/csdn-qq8864/hmmovie

好的作品是需要不断打磨,在你的学习和体验过程中有任何问题,欢迎到我的开源项目代码仓下面提交issue,持续优化。

安装nutpi/axios

首先,需要在项目中安装nutpi/axios库。

ohpm install @ohos/axios

在这里插入图片描述

实现电影搜索接口

使用nutpi/axios库来实现电影搜索接口。先封装一个工具类:

//axiosClient.ets
import {AxiosHttpRequest,HttpPromise} from '@nutpi/axios'
import {AxiosHeaders,AxiosRequestHeaders,AxiosError } from '@nutpi/axios';
import { Log } from './logutil';
import { promptAction } from "@kit.ArkUI";function showToast(msg:string){Log.debug(msg)promptAction.showToast({ message: msg })
}function showLoadingDialog(msg:string){Log.debug(msg)promptAction.showToast({ message: msg })
}function hideLoadingDialog() {}
/*** axios请求客户端创建*/
const axiosClient = new AxiosHttpRequest({baseURL: "http://120.27.146.247:8000/api/v1",timeout: 10 * 1000,checkResultCode: false,showLoading:true,headers: new AxiosHeaders({'Content-Type': 'application/json'}) as AxiosRequestHeaders,interceptorHooks: {requestInterceptor: async (config) => {// 在发送请求之前做一些处理,例如打印请求信息Log.debug('网络请求Request 请求方法:', `${config.method}`);Log.debug('网络请求Request 请求链接:', `${config.url}`);Log.debug('网络请求Request Params:', `\n${JSON.stringify(config.params)}`);Log.debug('网络请求Request Data:', `${JSON.stringify(config.data)}`);// 动态添加或修改header//config.headers['X-ATOMGIT-POP-COMMUNITY'] = 'openatom';axiosClient.config.showLoading = config.showLoadingif (config.showLoading) {showLoadingDialog("加载中...")}if (config.checkLoginState) {//let hasLogin = await StorageUtils.get(StorageKeys.USER_LOGIN, false)//Log.debug('网络请求Request 登录状态校验>>>', `${hasLogin.toString()}`);// if (hasLogin) {//   return config// } else {//   if (config.needJumpToLogin) {//     //Router.push(RoutePath.TestPage)//   }//   throw new AxiosError("请登录")// }}return config;},requestInterceptorCatch: (err) => {Log.error("网络请求RequestError", err.toString())if (axiosClient.config.showLoading) {hideLoadingDialog()}return err;},responseInterceptor: (response) => {//优先执行自己的请求响应拦截器,在执行通用请求request的if (axiosClient.config.showLoading) {hideLoadingDialog()}Log.debug('网络请求响应Response:', `\n${JSON.stringify(response.data)}`);if (response.status === 200) {// @ts-ignoreconst checkResultCode = response.config.checkResultCodeif (checkResultCode && response.data.errorCode != 0) {showToast(response.data.errorMsg)return Promise.reject(response)}return Promise.resolve(response);} else {return Promise.reject(response);}},responseInterceptorCatch: (error) => {if (axiosClient.config.showLoading) {hideLoadingDialog()}Log.error("网络请求响应异常", error.toString());errorHandler(error);return Promise.reject(error);},}
});function errorHandler(error: any) {if (error instanceof AxiosError) {//showToast(error.message)} else if (error != undefined && error.response != undefined && error.response.status) {switch (error.response.status) {// 401: 未登录// 未登录则跳转登录页面,并携带当前页面的路径// 在登录成功后返回当前页面,这一步需要在登录页操作。case 401:break;// 403 token过期// 登录过期对用户进行提示// 清除本地token和清空vuex中token对象// 跳转登录页面case 403://showToast("登录过期,请重新登录")// 清除token// localStorage.removeItem('token');break;// 404请求不存在case 404://showToast("网络请求不存在")break;// 其他错误,直接抛出错误提示default://showToast(error.response.data.message)}}
}export  {axiosClient,HttpPromise};

接口的实现很简单啦:

// 定义电影搜索接口
// 7.电影搜索接口
export const movieSearch =  (q:string,start:number,count:number): HttpPromise<SearchResp> => axiosClient.post({url:'/searchmovie',data: {  q:q,start:start,count:count }});

代码讲解

  1. 创建axios客户端:封装了一个axios客户端axiosClient工具类,并设置了基础URL和请求超时时间。
  2. 定义接口函数movieSearch函数接收三个参数:q(查询字符串)、start(起始位置)和count(数量),并返回一个Promise对象。

Search组件和List组件使用

接下来,将实现影视搜索页的组件,包括Search组件和List组件的使用。

import { movieSearch } from '../../common/api/movie';
import { SearchRespData } from '../../common/bean/SearchResp';
import { Log } from '../../utils/logutil';
import { BusinessError } from '@kit.BasicServicesKit';@Builder
export function SearchPageBuilder() {SearchPage()
}@Component
struct SearchPage {pageStack: NavPathStack = new NavPathStack()controller: SearchController = new SearchController()@State changeValue: string = ''@State submitValue: string = ''@State searchList: SearchRespData[] = []// 组件生命周期aboutToAppear() {Log.info('SearchPage aboutToAppear');}onPageShow(): void {this.controller.caretPosition(0)}build() {NavDestination() {Column({ space: 0 }) {Search({ controller: this.controller, value: this.changeValue, placeholder: '请输入片名' }).searchButton('搜索').width('95%').height(45).maxLength(30).backgroundColor('#F5F5F5').placeholderColor(Color.Grey).placeholderFont({ size: 14, weight: 400 }).textFont({ size: 14, weight: 400 }).focusable(true).defaultFocus(true).onSubmit((value: string) => {this.submitValue = value}).onChange((value: string) => {this.changeValue = valuemovieSearch(value, 1, 10).then((res) => {Log.debug(res.data.message)Log.debug("request", "res.data.code:%{public}d", res.data.code)if (res.data.code == 0) {this.searchList = res.data.data}}).catch((err: BusinessError) => {Log.debug("request", "err.data.code:%d", err.code)Log.debug("request", err.message)});}).margin({ left: 20, right: 20 })// list组件List({ space: 10 }) {ForEach(this.searchList, (item: SearchRespData, idx) => {ListItem() {Column({ space: 0 }) {Row() {Stack() {Image(item.cover).objectFit(ImageFit.Cover).borderRadius(5).zIndex(1)Text(item.year.substring(0, 10)).padding(5).margin({ top: 80 }).width('100%').height(20).textAlign(TextAlign.Center).maxLines(2).textOverflow({ overflow: TextOverflow.Clip }).fontSize(12).fontColor(Color.White).opacity(100) // 设置标题的透明度.backgroundColor('#808080AA') // 背景颜色设为透明.zIndex(2)}.width(100).height(100).margin({ left: 10 })Column({ space: 15 }) {Text(item.title).fontSize(16).fontWeight(FontWeight.Bold).align(Alignment.Start).width('100%')Text(item.genre).fontSize(12).align(Alignment.Start).width('100%')Text('评分: ' + item.rate).fontSize(12).align(Alignment.Start).width('100%')}.justifyContent(FlexAlign.Start).padding(5).margin({ left: 10 })}.size({ width: '100%', height: 100 })}.size({ width: '100%', height: 100 })}.onClick(() => {this.pageStack.pushDestinationByName("MovieDetailPage", { id: item.id }).catch((e: Error) => {console.log(`catch exception: ${JSON.stringify(e)}`)}).then(() => {// 跳转成功});})}, (itm: SearchRespData) => itm.id)}.divider({ strokeWidth: 2, color: '#F1F3F5' }).listDirection(Axis.Vertical).edgeEffect(EdgeEffect.Spring, { alwaysEnabled: true })}.width('100%').height('100%')}.title("影视搜索").width('100%').height('100%').onReady(ctx => {this.pageStack = ctx.pathStack})}
}

代码讲解

  1. 导入模块:导入了之前定义的movieSearch函数,以及一些其他必要的模块。
  2. 定义组件状态
    • changeValue:用于存储当前搜索框中的输入值。
    • submitValue:用于存储用户提交的搜索值。
    • searchList:用于存储搜索结果的列表。
  3. 组件生命周期
    • aboutToAppear:组件即将出现在页面时执行的日志记录。
    • onPageShow:组件显示时重置光标位置。
  4. 构建页面
    • NavDestination:定义页面的导航目的地。
    • Column:垂直布局容器。
    • Search:搜索框组件,设置了搜索按钮、宽度、高度、最大长度等属性,并绑定了onSubmitonChange事件。
    • List:列表组件,用于显示搜索结果。
      • ForEach:遍历searchList数组,为每个搜索结果项创建一个ListItem
      • ListItem:列表项组件,包含电影的封面、年份、标题、类型和评分。
      • onClick:点击列表项时,导航到电影详情页。
  5. 列表样式
    • divider:设置列表项之间的分隔线。
    • listDirection:设置列表的方向为垂直。
    • edgeEffect:设置边缘效果为弹簧效果。

总结

通过本文,展示了如何使用HarmonyOS NEXT框架和nutpi/axios库来实现一个简单的影视搜索页。nutpi/axios库的使用大大简化了网络请求的操作,使代码更加简洁易读。希望这篇文章对你有所帮助,让你在开发HarmonyOS NEXT应用时更加得心应手。

如果你有任何问题或建议,欢迎在评论区留言交流!

作者介绍

作者:csdn猫哥

原文链接:https://blog.csdn.net/yyz_1987

团队介绍

坚果派团队由坚果等人创建,团队拥有12个华为HDE带领热爱HarmonyOS/OpenHarmony的开发者,以及若干其他领域的三十余位万粉博主运营。专注于分享HarmonyOS/OpenHarmony、ArkUI-X、元服务、仓颉等相关内容,团队成员聚集在北京、上海、南京、深圳、广州、宁夏等地,目前已开发鸿蒙原生应用和三方库60+,欢迎交流。

版权声明

本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。


http://www.ppmy.cn/devtools/151743.html

相关文章

【深度学习】神经网络灾难性遗忘(Catastrophic Forgetting,CF)问题

文章目录 1. 什么是灾难性遗忘&#xff1f;2. 为什么会存在灾难性遗忘&#xff1f;2.1 网络权重的更新2.2 没有有效的记忆机制2.3 任务间数据分布差异 3. 目前解决方案3.1 弹性权重保持&#xff08;Elastic Weight Consolidation, EWC&#xff09;3.2 其他方法 1. 什么是灾难性…

【专题系列】华为堆叠场景-堆叠无法组建、堆叠异常分裂和堆叠快速升级异常处理

互联网各领域资料分享专区(不定期更新)&#xff1a; Sheet 堆叠无法组建 1、堆叠无法组建&#xff0c;首先排查两侧配置是否正确&#xff0c;主要为 DOMAIN、堆叠端口是否正确。通过 display stack configuration all 来查看。display stack troubleshooting 也能显示常见的配…

2019-腾讯Android面试精选题——谈一谈Binder的原理和实现一次拷贝的流程

####2.2 Linux 下的传统 IPC 通信原理 理解了上面的几个概念&#xff0c;我们再来看看传统的 IPC 方式中&#xff0c;进程之间是如何实现通信的。 通常的做法是消息发送方将要发送的数据存放在内存缓存区中&#xff0c;通过系统调用进入内核态。然后内核程序在内核空间分配内…

重拾Python学习,先从把python删除开始。。。

自己折腾就是不行啊&#xff0c;屡战屡败&#xff0c;最近终于找到前辈教我 第一步 删除Python 先把前阵子折腾的WSL和VScode删掉。还是得用spyder&#xff0c;跟matlab最像&#xff0c;也最容易入手。 从VScode上搞python&#xff0c;最后安装到appdata上&#xff0c;安装插…

【精选】基于EfficientViT优化YOLOv8的智能车辆识别系统设计 车辆颜色分类与车牌检测、深度学习目标检测系统开发

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

【深度学习项目】语义分割-FCN网络(原理、网络架构、基于Pytorch实现FCN网络)

文章目录 介绍深度学习语义分割的关键特点主要架构和技术数据集和评价指标总结 FCN网络FCN 的特点FCN 的工作原理FCN 的变体和发展FCN 的网络结构FCN 的实现&#xff08;基于Pytorch&#xff09;1. 环境配置2. 文件结构3. 预训练权重下载地址4. 数据集&#xff0c;本例程使用的…

openharmony标准系统芯片移植指导

标准系统移植指南 本文描述了移植一块开发板的通用步骤&#xff0c;和具体芯片相关的详细移植过程无法在此一一列举。后续社区还会陆续发布开发板移植的实例供开发者参考。 定义开发板 本文以移植名为MyProduct的开发板为例讲解移植过程&#xff0c;假定MyProduct是MyProduc…

服务器迁移MySQL

由于公司原有的服务器不再使用&#xff0c;需要将老的服务器上的MySQL迁移到新的服务器上&#xff0c;因此需要对数据进行备份迁移&#xff0c;前提是两台服务器已安装相同版本的MySQL&#xff0c;这里就不再讲解MySQL的安装步骤了&#xff0c;可以安装包、可以在线下载、可以容…