HarmonyOS NEXT:实现电影列表功能展示界面

时至今日HarmonyOS NEXT早已发布运行了,等其正式推出并大规模商用后,HarmonyOS的历史使命就完成并将退出历史舞台,为用户提供丰富的应用选择。但是Harmony NEXT是在HarmonyOS基础上剔除安卓(AOSP)后的产品,属于全新的手机系统。

今天实现一个简单的小案例,从零开始讲解如何通过鸿蒙开发实现一个电影列表功能的案例。

目录

新建初始项目

菜单与电影页

数据接口封装

加载与适配页

电影列表界面


新建初始项目

进入到编辑器中点击左上角的文件点击新建项目,然后选择空的 Empty Ability 进行创建:

然后接下来输入自己的项目名称就行,点击finish即可:

运行本地预览器,可以看到我们的初始项目已经跑通:

菜单与电影页

接下来开始编写我们类似H5端的tabBar导航菜单按钮的功能,这里我们可以借助官网给我们提供的选项卡(Tabs)进行类似的操作,如下所示:

接下来我们开始使用这个tabs选项卡的功能,首选我们先在pages目录下新建两个ArkTS文件然后把这两个文件都暴露出去,如下所示:

然后我们在index.ets文件下通过模块导入的方式,将两个文件进行一个导入,代码如下:

import Home from './home'
import Cinema from './cinema'@Entry
@Component
struct Index {build() {Tabs({ barPosition: BarPosition.End }) {TabContent() {Home().height('100%')}.tabBar("电影")TabContent() {Cinema().height('100%')}.tabBar("影院")}}
}

效果如下所示:

接下来我们就可以在首页组件中撰写相应的首页内容,这里我们也是借助了官方文档中的轮播器进行实现轮播图的操作,具体的代码如下所示:

@Component
struct Home {@State flag: boolean = trueimgList: string[] = ["http://124.223.69.156:5500/h5-01.jpg","http://124.223.69.156:5500/h5-02.jpg","http://124.223.69.156:5500/h5-03.png",]build() {Scroll() {Column() {// 轮播图Swiper() {ForEach(this.imgList, (item: string) => {Image(item).width('100%').height(180)})}.autoPlay(true) // 自动轮播.loop(true) // 无缝衔接// 即将上映Flex({ justifyContent: FlexAlign.SpaceAround }) {Text('正在热映').padding(10).border({ width: { bottom: this.flag ? 3 : 0 } }).borderColor(Color.Red).onClick(() => this.flag = true)Text('即将上映').padding(10).border({ width: { bottom: !this.flag ? 3 : 0 } }).borderColor(Color.Red).onClick(() => this.flag = false)}.margin({ top: 10, bottom: 10 })if (this.flag) {Text('正在热映')} else {Text('即将上映')}}}}
}
export default Home

最终呈现的效果如下所示:

上面我们仅仅是实现了静态页面的内容,如果想实现动态渲染的话就需要调用相应的接口函数,这里我们可以借助官方给我们提供的第三方仓库,网站:地址 如下所示:

然后我们下载我们调用接口的第三方库,终端执行如下命令进行安装:

ohpm install @ohos/axios

然后我们可以在项目的该文件下可以查看项目中安装的相关依赖信息:

数据接口封装

接下来开始对我们调用第三方接口进行一个初始的axios数据封装,在ets目录下新建utils工具目录,然后在工具目录当中封装如下的数据:

import axios, { AxiosResponse } from "@ohos/axios"// 参数统一处理
interface options_type {url: string,method?: string,data?: object,params?: object,headers?: object
}
// 请求返回类型
interface request_dataType {status: number,msg?: string,data: object
}// 创建axios实例
const request = axios.create({baseURL: "https://m.maizuo.com/",headers: {'X-Client-Info': '{"a":"3000","ch":"1002","v":"5.0.4","e":"1596502176387264316178433","bc":"310100"}'}
})
const http = (options: options_type) => {const method = options.method || 'GET'if (method.toLowerCase() === 'get') {options.params = options.data}return request(options)
}
// 针对请求返回的结果处理
const resultFn = async<T> (options: options_type): Promise<T> => {const result: AxiosResponse<request_dataType> = await http(options)return result.data as T
}export default resultFn

然后接下来我们继续在ets目录下新建api目录,用于存放后期的api文件,这里我们新建home.ets文件,然后在该文件中编写对应的home页的内容数据:

import request from '../utils/request'interface return_Home_type {files: filems[],total: number
}
interface filems {poster?: string,name?: string,filmId: number,nation: string,runtime: number,actors: [name: string]
}
interface myHeader {"X-Host": string
}// 获取首页数据
export const getHomeData = (page: number) => {return request<return_Home_type>({url: `gateway?cityId=310100&pageNum=${page}&pageSize=15&type=1&k=266615`,headers: {"X-Host": "mall.film-ticket.film.list"} as myHeader,method: "GET"})
}

然后我们在首页中通过调用生命周期函数 aboutToAppear ,在页面加载之前调用函数打印数据:

然后我们调用写好的接口函数获取对应的数据:

aboutToAppear(): void {getHomeData(this.page).then(res => {console.log(JSON.stringify(res))this.moveData.films = res.films?.map((item: filems) => {item.poster = item.poster?.replace("pic.maizuo.com", "static.maizuo.com/pc/v5")return item})})
}

通过props的方式,将获取到的接口数据传递给子组件:

import { return_Home_type, filems, actors_type } from '../api/home'@Component
struct MoveList {@Prop moveData: return_Home_type@Link page: number// 处理参演人员数据fillter_actors(arr: actors_type[] | undefined) {if (!arr) return "暂无主演"return arr.map((item: actors_type) => {return item.name}).join(' ') // 通过数组转为字符串,用空格拼接}build() {Column() { // 兼容不同的终端GridRow({ gutter: { y: 20 } }) {ForEach(this.moveData.films, (item: filems) => {GridCol({span: { sm:12, md:6, lg: 3 }}) {Flex({ justifyContent: FlexAlign.SpaceBetween }) {Image(item.poster).width('20%').height(100).margin({ right: 10 })Column() {Text(item.name).fontSize(20).fontWeight(FontWeight.Bold).lineHeight(30)Text(this.fillter_actors(item.actors))Row() {Text(item.nation + '|').fontSize(15)Text(`${item.runtime}`).fontSize(15)}}.alignItems(HorizontalAlign.Start).width('80%')}.padding(10)}})}}}
}export default MoveList

最终呈现的效果如下所示:

加载与适配页

为了实现性能上的优化,这里我们需要实现一下下拉加载更多的功能,在Scroll容器当中是有下拉触底的函数的,这里我们简单的调用一下:

为了方便调用,这里我们将之前获取数据的函数抽离一下:

// 请求电影列表数据
getMovieData() {getHomeData(this.page).then(res => {this.moveData.films = res.films?.map((item: filems) => {item.poster = item.poster?.replace("pic.maizuo.com", "static.maizuo.com/pc/v5")return item})// 如果是第一页则直接覆盖move_dataif (this.page === 1) {this.moveData = res} else {// 如果是其他页则直接对films进行拼接(this.moveData as return_Home_type).films =(this.moveData as return_Home_type).films?.concat(res.films as filems[])}})
}
aboutToAppear(): void {this.getMovieData()
}

最终呈现的效果如下所示:

接下来我们给其加上一个回到顶部的按钮,这里我们首先需要给滚动容器创建实例:

然后设置停止滚动触发的函数,然后根据条件的判断来动态显示按钮:

在列表界面,调用屏幕适配变化的函数,来动态的调用获取数据的函数:

呈现的效果如下所示:

电影列表界面

接下来开始实现影院列表界面,首先我们先编写相应的接口函数,代码如下所示:

import request from '../utils/request'interface MyHeader {"X-Host": string
}
interface return_cinema_type {cinemas: cinemas[]
}
export interface cinemas {name: string,address: string
}
interface return_city_type {cities: cities[]
}
export  interface cities {name: string,cityId: number
}
// 获取影院列表
export const getCinemaData = (cityId: number) => {return request<return_cinema_type>({url: `gateway?cityId=${cityId}&ticketFlag=1&k=2500238`,headers: {"X-Host": "mall.film-ticket.cinema.list"} as MyHeader,method: "get"})
}
// 获取城市列表
export const getCity = () => {return request<return_city_type>({url: `gateway?k=2323064`,headers: {"X-Host": "mall.film-ticket.cinema.list"} as MyHeader,method: "get"})
}

接下来我们开始编写对应的影院列表内容数据的布局:

@Component
struct Cinema {@State cityName: string = '上海' // 城市名称@State cityId: number = 310100@State cinemas: cinemas[] = [] // 影院列表cityDialog: CustomDialogController = new CustomDialogController({builder: CityDialog({updateCity: (city: cities) => { this.updateCity(city) }})})updateCity(city: cities) {// 关闭弹框this.cityDialog.close()// 调用列表接口this.getData(city.cityId)// 修改显示名称this.cityName = city.name}// 请求数据getData(cityId: number) {getCinemaData(cityId).then(res=>{this.cinemas = res.cinemas})}aboutToAppear(): void {this.getData(this.cityId)}build() {Scroll() {Column() {Text(this.cityName).width('100%').margin({ bottom: 10 }).textAlign(TextAlign.Center).onClick(()=>{// 展示弹框this.cityDialog.open()})ForEach(this.cinemas, (item: cinemas) => {Text(item.name).fontSize(18).margin({ left: 5 })Text(item.address).fontSize(15).fontColor(Color.Gray).margin({ left: 5 })})}.alignItems(HorizontalAlign.Start)}}
}
export default Cinema

这里我们用到了一个弹框的效果,代码如下所示:

// 创建城市弹框
@CustomDialog
@Component
struct CityDialog {@State cities: cities[] = []controller: CustomDialogController// 定义父组件传入的通信函数updateCity: (city: cities) => void = () => {}aboutToAppear(): void {getCity().then(res => {this.cities = res.cities})}build() {Scroll() {Text('请选择城市').fontSize(20).fontColor(Color.Red).margin(5).padding(5).border({ width: { bottom: 1 } })ForEach(this.cities, (item: cities) => {Text(item.name).width('100%').height(50).textAlign(TextAlign.Center).onClick(() => {this.updateCity(item)})})}}
}

最终呈现的效果如下所示:

具体的界面搭建与接口调用参考的是 卖座电影 的一个H5案例,如下所示:

截止现在,一个简易的电影列表展示内容已经做完了,大家可以自行去练习一下!

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

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

相关文章

自动驾驶系列—自动驾驶MCU架构全方位解析:从单核到多核的选型指南与应用实例

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

图说几何学2300年重大错误:附着在直线z上的直线段必是z的一部分

黄小宁 用泡沫塑料和油漆制成的铅球与真正的铅球&#xff0c;两者有不同的内部形状。同样&#xff0c;数学有长度相同但内部形状不同的伪≌直线段。 几何学有史2300年来一直认定附着在直线z上的直线段一定是z的一部分。其实这是2300年肉眼直观错觉——百年病态集论的症结。 …

工作笔记【四】

对于这种&#xff0c;样式一样&#xff0c;但是图片和字体颜色不一样&#xff0c;动态渲染。 代码&#xff1a; <template><view class"page"><view class"rows" v-for"item in data"><view class"v0"><v…

代码随想录算法训练营第四八天| 739. 每日温度 496.下一个更大元素 I 503.下一个更大元素II

今日任务 739. 每日温度 496.下一个更大元素 I 503.下一个更大元素II 739. 每日温度 题目链接&#xff1a; . - 力扣&#xff08;LeetCode&#xff09; class Solution {public int[] dailyTemperatures(int[] temperatures) {Stack<Integer> stack new Stack<Int…

基于解压缩模块的JPEG同步重压缩检测论文学习

一、论文基本信息&#xff1a; 论文题目&#xff1a;基于解压缩模块的JPEG同步重压缩检测 作者&#xff1a;王金伟1 &#xff0c;胡冰涛1 &#xff0c;张家伟1 &#xff0c;马 宾2 &#xff0c;罗向阳3 &#xff08;1.南京信息工程大学计算机学院、网络空间安全学院&#xf…

Footprint Growthly Quest 工具:赋能 Telegram 社区实现 Web3 飞速增长

作者&#xff1a;Stella L (stellafootprint.network) 在 Web3 的快节奏世界里&#xff0c;社区互动是关键。而众多 Web3 社区之所以能够蓬勃发展&#xff0c;很大程度上得益于 Telegram 平台。正因如此&#xff0c;Footprint Analytics 精心打造了 Growthly —— 一款专为 Tel…

阿里大模型算法岗面试,上来就手撕代码啊

最近已有不少大厂都在秋招宣讲了&#xff0c;也有一些在 Offer 发放阶段。 节前&#xff0c;我们邀请了一些互联网大厂朋友、今年参加社招和校招面试的同学。 针对新手如何入门算法岗、该如何准备面试攻略、面试常考点、大模型技术趋势、算法项目落地经验分享等热门话题进行了…

怎样才能写出好的知识竞赛活动策划方案

好的知识竞赛活动策划方案是抄不会的&#xff0c;尤其是抄一堆烂方案的话&#xff0c;只会让你走偏。首要的是建立策划底层思维&#xff0c;搞清楚如何从策划角度思考问题和解决问题。注意读、思、学&#xff0c;读&#xff1a;大量读策划案例和营销案例&#xff0c;分析总结和…

木舟0基础学习Java的第三十一天(SpringMVC,xml式和注解式开发,携带数据,取值,视图解析)

SpringMVC Mybatis: 优化了dao层 降低了java与dao层的耦合 Spring:是大管家 整合和管理mybatis与springmve(是spring中子模块) SpringMVC:优化了servlet层 降低了java与servlet的耦合 为什么要使用 springMVC? SpringMVC 是一种基于 Java&#xff0c;实现了 Web MVC 设计模…

当贝播放器 1.5.0 畅享原画,支持阿里网盘、杜比视界和8K播放

当贝播放器TV是一款专为智能电视设计的视频播放器&#xff0c;具有强大的解码能力&#xff0c;支持阿里网盘、百度网盘等网盘资源导入。此外&#xff0c;还支持外部设备导入&#xff0c;并能自动匹配电影海报封面、内容介绍和剧照。 大小&#xff1a;47.3M 百度网盘&#xff1…

Python与MongoDB交互

Python与MongoDB的交互通常通过pymongo库来实现。pymongo是一个官方的Python驱动程序&#xff0c;用于与MongoDB数据库进行交互。以下是一个简单的示例&#xff0c;展示了如何使用pymongo来连接到MongoDB数据库&#xff0c;执行一些基本的数据库操作&#xff08;如插入、查询、…

js 实现视频封面截图

今天给大家分享一下&#xff0c;如何实现视频封面截取功能&#xff0c;这里主要用到了 HTML5 的 canvas 相关的 api 和 js 相关的一些知识&#xff0c;话不多说&#xff0c;直接上代码&#xff1a; <template><div><div class"margin-tb-sm"><…

【ARM】MDK-当选择AC5时每次点击build都会全编译

【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 解决MDK中选择AC5时每次点击build都会全编译 2、 问题场景 在MDK中点击build时&#xff0c;正常会只进行增量编译&#xff0c;但目前每次点击的时候都会全编译。 3、软硬件环境 1 软件版本&#xff1a;Keil MDK 5.…

html+css+js实现dialog对话框

实现效果 HTML部分 <span class"text">点击打开 Dialog</span><!-- 警告框 --><div class"alert"><div class"header"><i>X</i> </div><div class"content">确认关闭</di…

基于php的律所管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

【git】通过配置 `init.defaultBranch`,自定义 Git 初始化时的默认分支名称,避免使用 `master` 并消除相关的警告提示

Git 会提示你配置一个默认的初始分支名称 git init 提示&#xff1a;使用 ‘master’ 作为初始分支的名称。这个默认分支名称可能会更改。要在新仓库中 提示&#xff1a;配置使用初始分支名&#xff0c;并消除这条警告&#xff0c;请执行&#xff1a; 提示&#xff1a; 提示&am…

从0开始深度学习(6)——Pytorch动态图机制(前向传播、反向传播)

PyTorch 的动态计算图机制是其核心特性之一&#xff0c;它使得深度学习模型的开发更加灵活和高效。 0 计算图 计算图&#xff08;Computation Graph&#xff09;是一种用于表示数学表达式或程序流程的图形结构&#xff0c;可以将复杂的表达式分解成一系列简单的操作&#xff0…

详解代理模式-【静态代理与JDK动态代理】(非常的斯国一)

目录 静态代理 什么是静态代理: ​ 特点: 例子&#xff1a; JDK动态代理&#xff08;主要讲点&#xff09; 大纲&#xff1a; 1、与静态代码的联系 2、JDK动态代理的主流程 3、Proxy的源码 整体概述&#xff1a; 重要点的翻译 &#xff1a; newProxyInstance源码&am…

深信服2025届全球校招研发笔试-C卷(AK)

前面14个填空题 T1 已知 子数组 定义为原数组中的一个连续子序列。现给定一个正整数数组 arr&#xff0c;请计算该数组内所有可能的奇数长度子数组的数值之和。 输入描述 输入一个正整数数组arr 输出描述 所有可能的奇数长度子数组的和 示例 1 输入 1,4,2,5,3 输出 58 说明 …

C++11智能智能指针解析

C11 引入了 智能指针来解决手动管理动态内存的复杂性。它们能够自动管理堆内存&#xff0c;并在不再需要时自动释放&#xff0c;避免内存泄漏和悬空指针问题。C11 提供了三种主要的智能指针类型&#xff1a;std::unique_ptr、std::shared_ptr 和 std::weak_ptr。 1. std::uniq…