HarmonyOS NEXT应用开发边学边玩系列:从零实现一影视APP (三、影视搜索页功能实现)
2025-01-14 16:37:02
9次阅读
0个评论
最后修改时间:2025-01-14 16:45:03
在HarmonyOS NEXT开发环境中,我们可以使用
@nutpi/axios
库来简化网络请求的操作。本文将展示如何使用HarmonyOS NEXT框架和@nutpi/axios
库,从零开始实现一个简单的影视APP,主要关注影视搜索页的功能实现。
为什么选择@nutpi/axios
?
nutpi/axios
是坚果派出品的,对axios封装过的鸿蒙HTTP客户端库,用于简化axios库的使用和以最简单的形式写代码。使用nutpi/axios
库可以大大简化代码,使网络接口变得简单直观。
项目开源地址:https://atomgit.com/csdn-qq8864/hmmovie
安装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.showLoading
if (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-ignore
const checkResultCode = response.config.checkResultCode
if (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 }});
代码讲解
- 创建axios客户端:我们封装了一个axios客户端
axiosClient
工具类,并设置了基础URL和请求超时时间。 - 定义接口函数:
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 = value
movieSearch(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
})
}
}
代码讲解
- 导入模块:我们导入了之前定义的
movieSearch
函数,以及一些其他必要的模块。 - 定义组件状态:
changeValue
:用于存储当前搜索框中的输入值。submitValue
:用于存储用户提交的搜索值。searchList
:用于存储搜索结果的列表。
- 组件生命周期:
aboutToAppear
:组件即将出现在页面时执行的日志记录。onPageShow
:组件显示时重置光标位置。
- 构建页面:
NavDestination
:定义页面的导航目的地。Column
:垂直布局容器。Search
:搜索框组件,设置了搜索按钮、宽度、高度、最大长度等属性,并绑定了onSubmit
和onChange
事件。List
:列表组件,用于显示搜索结果。ForEach
:遍历searchList
数组,为每个搜索结果项创建一个ListItem
。ListItem
:列表项组件,包含电影的封面、年份、标题、类型和评分。onClick
:点击列表项时,导航到电影详情页。
- 列表样式:
divider
:设置列表项之间的分隔线。listDirection
:设置列表的方向为垂直。edgeEffect
:设置边缘效果为弹簧效果。
总结
通过本文,我们展示了如何使用HarmonyOS NEXT框架和nutpi/axios
库来实现一个简单的影视搜索页。nutpi/axios
库的使用大大简化了网络请求的操作,使代码更加简洁易读。希望这篇文章对你有所帮助,让你在开发HarmonyOS NEXT应用时更加得心应手。
如果你有任何问题或建议,欢迎在评论区留言交流!
00
- 3回答
- 3粉丝
- 5关注
相关话题
- HarmonyOS NEXT应用开发实战(一):边学边玩,从零开发一款影视APP
- HarmonyOS NEXT边学边玩,从零开发一款影视APP(二、首页轮播图懒加载的实现)
- HarmonyOS NEXT应用开发边学边玩,从零实现一影视APP(四、最近上映电影滚动展示及加载更多的实现)
- 鸿蒙HarmonyOS从零实现类微信app基础界面搭建
- 【HarmonyOS NEXT】实现页面水印功能
- 鸿蒙next boss直聘招聘app 聊天功能实现来
- 【HarmonyOS NEXT】 Audio 实现录音及播放功能
- 【HarmonyOS NEXT】Tabs组件实现类微信(可滑动的)tabBar页签切换页面功能
- 从零到智能:打造智能灯控应用
- HarmonyOS应用开发实战:半天实现知乎日报项目(八、知乎日报详情页的实现)
- 【HarmonyOS NEXT】权限申请及应用设置页跳转
- 【HarmonyOS NEXT】权限申请及应用设置页跳转
- HarmonyOS应用开发实战:半天实现知乎日报项目(三、ArkUI页面底部导航TabBar的实现)
- HarmonyOS NEXT 应用开发实战:音乐播放器的完整实现
- HarmonyOS NEXT:模块化项目 ——修改应用图标+启动页等