HarmonyOS NEXT应用开发边学边玩系列:从零实现一影视APP (四、最近上映电影滚动展示及加载更多的实现)

news2025/3/10 5:22:32

在HarmonyOS NEXT开发环境中,可以使用多种组件和库来构建丰富且交互友好的应用。本文将展示如何使用HarmonyOS NEXT框架和nutpi/axios库,从零开始实现一个简单的影视APP的首页,主要关注最近上映电影的滚动展示及加载更多功能的实现。

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

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

安装nutpi/axios

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

ohpm install @ohos/axios

在这里插入图片描述

实现最近上映电影接口

使用nutpi/axios库来实现最近上映电影的接口请求。接口请求如下:

import {axiosClient,HttpPromise} from '../../utils/axiosClient';
import { HotMovieReq, MovieRespData, SwiperData } from '../bean/ApiTypes';

// 1.获取轮播图接口
export const getSwiperData = (): HttpPromise<SwiperData> => axiosClient.get({url:'/swiperdata'});

// 2.获取即将上映影视接口
export const getSoonMovie = (start:number,count:number): HttpPromise<MovieRespData> => axiosClient.post({url:'/soonmovie',data: { start:start,count:count }});

// 3.获取热门影视接口
export const getHotMovie = (req:HotMovieReq): HttpPromise<MovieRespData> => axiosClient.post({url:'/hotmovie',data:req});

代码讲解

  1. 创建axios客户端:创建了一个axios客户端axiosClient,并设置了基础URL和请求超时时间。
  2. 定义接口函数getSoonMovies函数向接口发送GET请求以获取最近上映的电影数据,并返回一个Promise对象。

实现首页组件

接下来,将实现首页组件,包括最近上映电影的滚动展示和加载更多功能。

import { getSoonMovies } from '../../common/api/movie';
import { MovieItem } from '../../common/bean/MovieItem';
import { Log } from '../../utils/logutil';
import { NavPathStack } from '@ohos.router';
import { BusinessError } from '@kit.BasicServicesKit';

@Builder
export function HomePageBuilder() {
  HomePage()
}

@Component
struct HomePage {
  pageStack: NavPathStack = new NavPathStack()
  @State soonMvList: MovieItem[] = []

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

  // 获取最近上映电影数据
  fetchSoonMovies() {
    getSoonMovies().then((res) => {
      Log.debug(res.data.message)
      Log.debug("request", "res.data.code:%{public}d", res.data.code)
      if (res.data.code == 0) {
        this.soonMvList = res.data.data
      }
    })
    .catch((err: BusinessError) => {
      Log.debug("request", "err.data.code:%d", err.code)
      Log.debug("request", err.message)
    });
  }

  build() {
    Column({ space: 0 }) {
      Flex({
        direction: FlexDirection.Row,
        justifyContent: FlexAlign.SpaceBetween,
        alignContent: FlexAlign.SpaceBetween
      }) {
        Text('即将上映').fontWeight(FontWeight.Bold)
        Text('加载更多 >>').fontSize(14).fontColor(Color.Black)
          .onClick(() => {
            this.pageStack.pushDestinationByName("MovieMorePage", { types: 1 }).catch((e: Error) => {
              console.log(`catch exception: ${JSON.stringify(e)}`)
            }).then(() => {
              // 跳转成功
            });
          })
      }.padding(10)

      Scroll() {
        Row({ space: 5 }) {
          ForEach(this.soonMvList, (item: MovieItem) => {
            Column({ space: 0 }) {
              Image(item.cover).objectFit(ImageFit.Auto).height(160).borderRadius(5)
                .onClick(() => {
                  this.pageStack.pushDestinationByName("MovieDetailPage", { id: item.id }).catch((e: Error) => {
                    console.log(`catch exception: ${JSON.stringify(e)}`)
                  }).then(() => {
                    // 跳转成功
                  });
                })

              Text(item.title)
                .alignSelf(ItemAlign.Center)
                .maxLines(1)
                .textOverflow({ overflow: TextOverflow.Ellipsis })
                .width(100)
                .fontSize(14).fontWeight(FontWeight.Bold).padding(10)
            }.justifyContent(FlexAlign.Center)
          }, (itm: MovieItem) => itm.id)
        }
      }.scrollable(ScrollDirection.Horizontal)
    }
    .width('100%')
    .height('100%')
  }
}

代码讲解

  1. 导入模块:导入了之前定义的getSoonMovies函数,以及一些其他必要的模块。
  2. 定义组件状态
    • soonMvList:用于存储最近上映电影的数据。
  3. 组件生命周期
    • aboutToAppear:组件即将出现在页面时执行的日志记录,并调用fetchSoonMovies函数获取数据。
  4. 构建页面
    • Column:垂直布局容器。
    • Flex:弹性布局容器,用于布局“即将上映”和“加载更多”按钮。
      • Text('即将上映'):显示“即将上映”标题。
      • Text('加载更多 >>'):显示“加载更多”按钮,并设置点击事件,点击时导航到加载更多页面。
    • Scroll:滚动容器,设置为水平滚动。
      • Row:水平布局容器,用于放置电影项。
      • ForEach:遍历soonMvList数组,为每个电影项创建一个Column
        • Column:垂直布局容器,用于放置电影的图片和标题。
          • Image:显示电影封面图片,并设置点击事件,点击时导航到电影详情页面。
          • Text:显示电影标题,并设置样式。

配置路由

为了实现页面跳转,需要在entry/src/main/resources/base/profile路径下的route_map.json文件中配置路由。

{
  "routerMap": [
    {
      "name": "HomePage",
      "pageSourceFile": "src/main/ets/pages/home/Home.ets",
      "buildFunction": "HomePageBuilder",
      "data": {
        "description": "this is HomePage"
      }
    },
    {
      "name": "MovieMorePage",
      "pageSourceFile": "src/main/ets/pages/home/MovieMore.ets",
      "buildFunction": "MovieMorePageBuilder",
      "data": {
        "description": "this is MovieMorePage"
      }
    },
    {
      "name": "MovieDetailPage",
      "pageSourceFile": "src/main/ets/pages/home/Detail.ets",
      "buildFunction": "MovieDetailPageBuilder",
      "data": {
        "description": "this is MovieDetailPage"
      }
    }
  ]
}

代码讲解

  1. 配置路由
    • HomePage:配置首页的路由信息。
    • MovieMorePage:配置加载更多页面的路由信息。
    • MovieDetailPage:配置电影详情页面的路由信息。

涉及到的常用组件

Flex

Flex组件用于创建弹性布局容器,可以控制子组件的排列方式和对齐方式。

Flex({
  direction: FlexDirection.Row,
  justifyContent: FlexAlign.SpaceBetween,
  alignContent: FlexAlign.SpaceBetween
}) {
  Text('即将上映').fontWeight(FontWeight.Bold)
  Text('加载更多 >>').fontSize(14).fontColor(Color.Black)
}

Scroll

Scroll组件用于创建可滚动的容器,可以设置滚动方向为水平或垂直。

Scroll() {
  Row({ space: 5 }) {
    ForEach(this.soonMvList, (item: MovieItem) => {
      Column({ space: 0 }) {
        Image(item.cover).objectFit(ImageFit.Auto).height(160).borderRadius(5)
      }
    }, (itm: MovieItem) => itm.id)
  }
}.scrollable(ScrollDirection.Horizontal)

ForEach

ForEach组件用于遍历数组并为每个元素生成一个子组件。

ForEach(this.soonMvList, (item: MovieItem) => {
  Column({ space: 0 }) {
    Image(item.cover).objectFit(ImageFit.Auto).height(160).borderRadius(5)
  }
}, (itm: MovieItem) => itm.id)

Image

Image组件用于显示图片,可以设置图片的显示方式、大小和形状。

Image(item.cover).objectFit(ImageFit.Auto).height(160).borderRadius(5)

Text

Text组件用于显示文本,可以设置文本的大小、颜色、对齐方式等。

Text(item.title).fontSize(14).fontWeight(FontWeight.Bold).padding(10)

ColumnRow

ColumnRow组件分别用于创建垂直和水平布局容器。

Column({ space: 0 }) {
  // 子组件
}

Row({ space: 5 }) {
  // 子组件
}

onClick

onClick事件用于处理组件的点击事件。

Text('加载更多 >>').fontSize(14).fontColor(Color.Black)
  .onClick(() => {
    this.pageStack.pushDestinationByName("MovieMorePage", { types: 1 }).catch((e: Error) => {
      console.log(`catch exception: ${JSON.stringify(e)}`)
    }).then(() => {
      // 跳转成功
    });
  })

总结

通过本文,展示了如何使用HarmonyOS NEXT框架和nutpi/axios库来实现一个简单的影视APP的首页,包括最近上映电影的滚动展示和加载更多功能。nutpi/axios库的使用大大简化了网络请求的操作,使代码更加简洁易读。同时,还介绍了涉及到的常用组件的使用方法。

希望这篇文章对你有所帮助,让你在开发HarmonyOS NEXT应用时更加得心应手。如果你有任何问题或建议,欢迎在评论区留言交流!

参考代码

以下是完整的HomePage组件代码:


import { Log } from '../../utils/logutil';
import { BusinessError } from '@kit.BasicServicesKit';
import { router } from '@kit.ArkUI';
import { MovieItem, SwiperItem } from '../../common/bean/ApiTypes';
import { getHotMovie, getHotTv,
  getMvTop250,
  getNewMovie,
  getPiaoMovie,
  getSoonMovie, getSwiperData, getUsHotMv } from '../../common/api/movie';
import { PiaoFangRespData } from '../../common/bean/PiaoFangResp';


class BasicDataSource<T> implements IDataSource {

  private listeners: DataChangeListener[] = [];
  private originDataArray: T[] = [];

  totalCount(): number {
    return this.originDataArray.length;
  }

  getData(index: number): T {
    return this.originDataArray[index];
  }

  registerDataChangeListener(listener: DataChangeListener): void {
    if (this.listeners.indexOf(listener) < 0) {
      this.listeners.push(listener);
    }
  }

  unregisterDataChangeListener(listener: DataChangeListener): void {
    const pos = this.listeners.indexOf(listener);
    if (pos >= 0) {
      this.listeners.slice(pos, 1);
    }
  }

  // 通知LazyForEach组件需要重新重载所有子组件
  notifyDataReload(): void {
    this.listeners.forEach(listener => {
      listener.onDataReloaded();
    })
  }

  // 通知LazyForEach组件需要在index对应索引处添加子组件
  notifyDataAdd(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataAdd(index);
    })
  }
}

class SwiperDataSource<T> extends BasicDataSource<T> {

  private dataArray: T[] = [];

  totalCount(): number {
    return this.dataArray.length;
  }

  getData(index: number): T {
    return this.dataArray[index];
  }

  // 在列表末尾添加数据并通知监听器
  pushData(data: T): void {
    this.dataArray.push(data);
    this.notifyDataAdd(this.dataArray.length - 1);
  }

  // 重载数据
  reloadData(): void {
    // 不会引起状态变化
    this.dataArray = [];
    // 必须通过DataChangeListener来更新
    this.notifyDataReload();
  }
}

@Component
export default struct Home {
  @Consume pageStack: NavPathStack
  private swiperController: SwiperController = new SwiperController()
  private swiperData: SwiperDataSource<SwiperItem> = new SwiperDataSource()
  @State soonMvList:MovieItem[]=[]
  @State hotMvList:MovieItem[]=[]
  @State hotTvList:MovieItem[]=[]
  @State usMvList:MovieItem[]=[]
  @State topMvList:MovieItem[]=[]
  @State piaoList:PiaoFangRespData[]=[]

  // 组件生命周期
  aboutToAppear() {
    Log.info('Home aboutToAppear');
    getSwiperData().then((res) => {
      Log.debug(res.data.message)
      Log.debug("request","res.data.code:%{public}d",res.data.code)
      for (const itm of res.data.data) {
        this.swiperData.pushData(itm)
      }
    }).catch((err: BusinessError) => {
      Log.debug("request","err.data.code:%d",err.code)
      Log.debug("request",err.message)
    });

    getPiaoMovie().then((res) => {
      Log.debug(res.data.message)
      for (const itm of res.data.data) {
        this.piaoList.push(itm)
      }

    }).catch((err: BusinessError) => {
      Log.debug("request","err.data.code:%d",err.code)
      Log.debug("request",err.message)
    });

    getSoonMovie(1,10).then((res) => {
      Log.debug(res.data.message)
      Log.debug("request","res.data.code:%{public}d",res.data.code)
      for (const itm of res.data.data) {
        this.soonMvList.push(itm)
      }
    }).catch((err: BusinessError) => {
      Log.debug("request","err.data.code:%d",err.code)
      Log.debug("request",err.message)
    });

    getHotMovie({start:1,count:10,city:'郑州'}).then((res) => {
      Log.debug(res.data.message)
      Log.debug("request","res.data.code:%{public}d",res.data.code)
      for (const itm of res.data.data) {
        this.hotMvList.push(itm)
      }
    }).catch((err: BusinessError) => {
      Log.debug("request","err.data.code:%d",err.code)
      Log.debug("request",err.message)
    });

    getHotTv(1,10).then((res) => {
      Log.debug(res.data.message)
      Log.debug("request","res.data.code:%{public}d",res.data.code)
      for (const itm of res.data.data) {
        this.hotTvList.push(itm)
      }
    }).catch((err: BusinessError) => {
      Log.debug("request","err.data.code:%d",err.code)
      Log.debug("request",err.message)
    });

    getUsHotMv(1,10).then((res) => {
      Log.debug(res.data.message)
      Log.debug("request","res.data.code:%{public}d",res.data.code)
      for (const itm of res.data.data) {
        this.usMvList.push(itm)
      }
    }).catch((err: BusinessError) => {
      Log.debug("request","err.data.code:%d",err.code)
      Log.debug("request",err.message)
    });

    getMvTop250(1,10).then((res) => {
      Log.debug(res.data.message)
      for (const itm of res.data.data) {
        this.topMvList.push(itm)
      }

    }).catch((err: BusinessError) => {
      Log.debug("request","err.data.code:%d",err.code)
      Log.debug("request",err.message)
    });
  }

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

  build() {
      Scroll() {
        Column({ space: 0 }) {
          //title
          Flex({
            direction: FlexDirection.Row,
            justifyContent: FlexAlign.SpaceBetween,
            alignContent: FlexAlign.SpaceBetween
          })
          {
            Blank().width(40)
            Text('爱影家').fontSize(26).fontWeight(FontWeight.Bold)
            Image($r('app.media.search')).width(42).height(42).padding({bottom:8}).onClick(() => {
              this.pageStack.pushDestinationByName("SearchPage", { }).catch((e:Error)=>{
                // 跳转失败,会返回错误码及错误信息
                console.log(`catch exception: ${JSON.stringify(e)}`)
              }).then(()=>{
                // 跳转成功
              });
            })
          }
          .padding(10)
          .width('100%').height(50)
          // 轮播图
          Swiper(this.swiperController) {
            LazyForEach(this.swiperData, (item: SwiperItem) => {
              Stack({ alignContent: Alignment.Center }) {
                Image(item.imageUrl)
                  .width('100%')
                  .height(180)
                  .zIndex(1)
                  .onClick(() => {
                    this.pageStack.pushDestinationByName("MovieDetailPage", { id:item.id }).catch((e:Error)=>{
                      // 跳转失败,会返回错误码及错误信息
                      console.log(`catch exception: ${JSON.stringify(e)}`)
                    }).then(()=>{
                      // 跳转成功
                    });
                  })

                // 显示轮播图标题
                Text(item.title)
                  .padding(5)
                  .margin({ top: 135 })
                  .width('100%')
                  .height(60)
                  .textAlign(TextAlign.Center)
                  .maxLines(2)
                  .textOverflow({ overflow: TextOverflow.Clip })
                  .fontSize(22)
                  .fontColor(Color.White)
                  .opacity(100)// 设置标题的透明度 不透明度设为100%,表示完全不透明
                  .backgroundColor('#808080AA')// 背景颜色设为透明
                  .zIndex(2)
                  .onClick(() => {
                    this.pageStack.pushDestinationByName("MovieDetailPage", { id:item.id }).catch((e:Error)=>{
                      // 跳转失败,会返回错误码及错误信息
                      console.log(`catch exception: ${JSON.stringify(e)}`)
                    }).then(()=>{
                      // 跳转成功
                    });
                  })
              }
            }, (item: SwiperItem) => item.id)
          }
          .cachedCount(2)
          .index(1)
          .autoPlay(true)
          .interval(4000)
          .loop(true)
          .indicatorInteractive(true)
          .duration(1000)
          .itemSpace(0)
          .curve(Curve.Linear)
          .onChange((index: number) => {
            console.info(index.toString())
          })
          .onGestureSwipe((index: number, extraInfo: SwiperAnimationEvent) => {
            console.info("index: " + index)
            console.info("current offset: " + extraInfo.currentOffset)
          })
          .height(180) // 设置高度
          Text('今日票房').fontWeight(FontWeight.Bold).padding(10).alignSelf(ItemAlign.Start)
          Scroll() {
            Row({ space: 5 }) {
              ForEach(this.piaoList, (item: PiaoFangRespData,idx) => {
                Column({ space: 2 }) {
                  Text(idx.toString()).fontSize(20).fontColor(Color.Orange)
                  Text(item.name)
                    .maxLines(1)
                    .textOverflow({ overflow: TextOverflow.Ellipsis })
                    .fontSize(14).fontWeight(FontWeight.Bold).alignSelf(ItemAlign.Center).padding(5)
                  Text(item.release_date).fontSize(12).fontColor(Color.White)
                    .alignSelf(ItemAlign.Center)
                  Text('票房:'+item.box_million).fontSize(12).fontColor(Color.White)
                    .alignSelf(ItemAlign.Center)
                  Text('占比:'+item.share_box).fontSize(12).fontColor(Color.White)
                    .alignSelf(ItemAlign.Center)

                }.width(120).height(120).backgroundColor('rgba(85, 170, 255, 0.60)').borderRadius(5).justifyContent(FlexAlign.Center)

              }, (itm: PiaoFangRespData, idx) => itm.name)
            }
          }.scrollable(ScrollDirection.Horizontal)

          Flex({
            direction: FlexDirection.Row,
            justifyContent: FlexAlign.SpaceBetween,
            alignContent: FlexAlign.SpaceBetween
          }) {
            Text('即将上映').fontWeight(FontWeight.Bold)
            Text('加载更多 >>').fontSize(14).fontColor(Color.Black) .onClick(() => {
              this.pageStack.pushDestinationByName("MovieMorePage", {types:1}).catch((e:Error)=>{
                // 跳转失败,会返回错误码及错误信息
                console.log(`catch exception: ${JSON.stringify(e)}`)
              }).then(()=>{
                // 跳转成功
              });
            })
          }.padding(10)
          Scroll() {
            Row({ space: 5 }) {
              ForEach(this.soonMvList, (item: MovieItem) => {
                Column({ space: 0 }) {
                  Image(item.cover).objectFit(ImageFit.Auto).height(160).borderRadius(5)
                    .onClick(() => {
                      this.pageStack.pushDestinationByName("MovieDetailPage", { id:item.id }).catch((e:Error)=>{
                        // 跳转失败,会返回错误码及错误信息
                        console.log(`catch exception: ${JSON.stringify(e)}`)
                      }).then(()=>{
                        // 跳转成功
                      });
                    })

                  Text(item.title)
                    .alignSelf(ItemAlign.Center)
                    .maxLines(1)
                    .textOverflow({ overflow: TextOverflow.Ellipsis })
                    .width(100)
                    .fontSize(14).fontWeight(FontWeight.Bold).padding(10)
                }.justifyContent(FlexAlign.Center)

              }, (itm: MovieItem, idx) => itm.id)
            }
          }.scrollable(ScrollDirection.Horizontal)

          Flex({
            direction: FlexDirection.Row,
            justifyContent: FlexAlign.SpaceBetween,
            alignContent: FlexAlign.SpaceBetween
          }) {
            Text('热映电影').fontWeight(FontWeight.Bold)
            Text('加载更多 >>').fontSize(14).fontColor(Color.Black) .onClick(() => {
              this.pageStack.pushDestinationByName("MovieMorePage", {types:2}).catch((e:Error)=>{
                // 跳转失败,会返回错误码及错误信息
                console.log(`catch exception: ${JSON.stringify(e)}`)
              }).then(()=>{
                // 跳转成功
              });
            })
          }.padding(10)
          Scroll() {
            Row({ space: 5 }) {
              ForEach(this.hotMvList, (item: MovieItem) => {
                Column({ space: 0 }) {
                  Image(item.cover).objectFit(ImageFit.Auto).height(160).borderRadius(5)
                    .onClick(() => {
                      this.pageStack.pushDestinationByName("MovieDetailPage", { id:item.id }).catch((e:Error)=>{
                        // 跳转失败,会返回错误码及错误信息
                        console.log(`catch exception: ${JSON.stringify(e)}`)
                      }).then(()=>{
                        // 跳转成功
                      });
                    })

                  Text(item.title)
                    .alignSelf(ItemAlign.Center)
                    .maxLines(1)
                    .textOverflow({ overflow: TextOverflow.Ellipsis })
                    .width(100)
                    .fontSize(14).fontWeight(FontWeight.Bold).padding(10)
                }.justifyContent(FlexAlign.Center)

              }, (itm: MovieItem, idx) => itm.id)
            }
          }.scrollable(ScrollDirection.Horizontal)

          // Flex({
          //   direction: FlexDirection.Row,
          //   justifyContent: FlexAlign.SpaceBetween,
          //   alignContent: FlexAlign.SpaceBetween
          // }) {
          //   Text('热门资讯').fontWeight(FontWeight.Bold)
          //   Text('加载更多 >>').fontSize(14).fontColor(Color.Black) .onClick(() => {
          //
          //   })
          // }.padding(10)
          Flex({
            direction: FlexDirection.Row,
            justifyContent: FlexAlign.SpaceBetween,
            alignContent: FlexAlign.SpaceBetween
          }) {
            Text('热门剧集').fontWeight(FontWeight.Bold)
            Text('加载更多 >>').fontSize(14).fontColor(Color.Black) .onClick(() => {
              this.pageStack.pushDestinationByName("MovieMorePage", {types:3}).catch((e:Error)=>{
                // 跳转失败,会返回错误码及错误信息
                console.log(`catch exception: ${JSON.stringify(e)}`)
              }).then(()=>{
                // 跳转成功
              });
            })
          }.padding(10)
          Scroll() {
            Row({ space: 5 }) {
              ForEach(this.hotTvList, (item: MovieItem) => {
                Column({ space: 0 }) {
                  Image(item.cover).objectFit(ImageFit.Auto).height(160).borderRadius(5)
                    .onClick(() => {
                      this.pageStack.pushDestinationByName("MovieDetailPage", { id:item.id }).catch((e:Error)=>{
                        // 跳转失败,会返回错误码及错误信息
                        console.log(`catch exception: ${JSON.stringify(e)}`)
                      }).then(()=>{
                        // 跳转成功
                      });
                    })

                  Text(item.title)
                    .alignSelf(ItemAlign.Center)
                    .maxLines(1)
                    .textOverflow({ overflow: TextOverflow.Ellipsis })
                    .width(100)
                    .fontSize(14).fontWeight(FontWeight.Bold).padding(10)
                }.justifyContent(FlexAlign.Center)

              }, (itm: MovieItem, idx) => itm.id)
            }
          }.scrollable(ScrollDirection.Horizontal)

          Flex({
            direction: FlexDirection.Row,
            justifyContent: FlexAlign.SpaceBetween,
            alignContent: FlexAlign.SpaceBetween
          }) {
            Text('豆瓣排行榜').fontWeight(FontWeight.Bold)
            Text('加载更多 >>').fontSize(14).fontColor(Color.Black) .onClick(() => {
              this.pageStack.pushDestinationByName("MovieMorePage", {types:4}).catch((e:Error)=>{
                // 跳转失败,会返回错误码及错误信息
                console.log(`catch exception: ${JSON.stringify(e)}`)
              }).then(()=>{
                // 跳转成功
              });
            })
          }.padding(10)
          Scroll() {
            Row({ space: 5 }) {
              ForEach(this.topMvList, (item: MovieItem) => {
                Column({ space: 0 }) {
                  Image(item.cover).objectFit(ImageFit.Auto).height(160).borderRadius(5)
                    .onClick(() => {
                      this.pageStack.pushDestinationByName("MovieDetailPage", { id:item.id }).catch((e:Error)=>{
                        // 跳转失败,会返回错误码及错误信息
                        console.log(`catch exception: ${JSON.stringify(e)}`)
                      }).then(()=>{
                        // 跳转成功
                      });
                    })

                  Text(item.title)
                    .alignSelf(ItemAlign.Center)
                    .maxLines(1)
                    .textOverflow({ overflow: TextOverflow.Ellipsis })
                    .width(100)
                    .fontSize(14).fontWeight(FontWeight.Bold).padding(10)
                }.justifyContent(FlexAlign.Center)

              }, (itm: MovieItem, idx) => itm.id)
            }
          }.scrollable(ScrollDirection.Horizontal)

          Flex({
            direction: FlexDirection.Row,
            justifyContent: FlexAlign.SpaceBetween,
            alignContent: FlexAlign.SpaceBetween
          }) {
            Text('北美票房榜').fontWeight(FontWeight.Bold)
            Text('加载更多 >>').fontSize(14).fontColor(Color.Black) .onClick(() => {
              this.pageStack.pushDestinationByName("MovieMorePage", {types:5}).catch((e:Error)=>{
                // 跳转失败,会返回错误码及错误信息
                console.log(`catch exception: ${JSON.stringify(e)}`)
              }).then(()=>{
                // 跳转成功
              });
            })
          }.padding(10)
          Scroll() {
            Row({ space: 5 }) {
              ForEach(this.usMvList, (item: MovieItem) => {
                Column({ space: 0 }) {
                  Image(item.cover).objectFit(ImageFit.Auto).height(160).borderRadius(5)
                    .onClick(() => {
                      this.pageStack.pushDestinationByName("MovieDetailPage", { id:item.id }).catch((e:Error)=>{
                        // 跳转失败,会返回错误码及错误信息
                        console.log(`catch exception: ${JSON.stringify(e)}`)
                      }).then(()=>{
                        // 跳转成功
                      });
                    })

                  Text(item.title)
                    .alignSelf(ItemAlign.Center)
                    .maxLines(1)
                    .textOverflow({ overflow: TextOverflow.Ellipsis })
                    .width(100)
                    .fontSize(14).fontWeight(FontWeight.Bold).padding(10)
                }.justifyContent(FlexAlign.Center)

              }, (itm: MovieItem, idx) => itm.id)
            }
          }.scrollable(ScrollDirection.Horizontal)

        }.width('100%')
      }
      .width('100%').height('100%')
      .scrollable(ScrollDirection.Vertical)
    }
}

作者介绍

作者:csdn猫哥

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

团队介绍

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

版权声明

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

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

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

相关文章

卷积神经05-GAN对抗神经网络

卷积神经05-GAN对抗神经网络 使用Python3.9CUDA11.8Pytorch实现一个CNN优化版的对抗神经网络 简单的GAN图片生成 CNN优化后的图片生成 优化模型代码对比 0-核心逻辑脉络 1&#xff09;Anacanda使用CUDAPytorch2&#xff09;使用本地MNIST进行手写图片训练3&#xff09;…

客户案例:某家居制造企业跨境电商,解决业务端(亚马逊平台)、易仓ERP与财务端(金蝶ERP)系统间的业务财务数据对账互通

一、系统定义 1、系统定位&#xff1a; 数据中台系统是一种战略选择和组织形式&#xff0c;通过有型的产品支撑和实施方法论&#xff0c;解决企业面临的数据孤岛、数据维护混乱、数据价值利用低的问题&#xff0c;依据企业特有的业务和架构&#xff0c;构建一套从数据汇聚、开…

服务器一次性部署One API + ChatGPT-Next-Web

服务器一次性部署One API ChatGPT-Next-Web One API ChatGPT-Next-Web 介绍One APIChatGPT-Next-Web docker-compose 部署One API ChatGPT-Next-WebOpen API docker-compose 配置ChatGPT-Next-Web docker-compose 配置docker-compose 启动容器 后续配置 同步发布在个人笔记服…

辅助云运维

为客户提供运维支持&#xff0c;保障业务连续性。 文章目录 一、服务范围二、服务内容三、服务流程四、 服务交付件五、责任分工六、 完成标志 一、服务范围 覆盖范围 云产品使用咨询、问题处理、配置指导等&#xff1b; 云产品相关操作的技术指导&#xff1b; 云相关资源日常…

[Qt]常用控件介绍-多元素控件-QListWidget、QTableWidget、QQTreeWidget

目录 1.多元素控件介绍 2.ListWidget控件 属性 核心方法 核心信号 细节 Demo&#xff1a;编辑日程 3.TableWidget控件 核心方法 QTableWidgetItem核心信号 QTableWidgetItem核心方法 细节 Demo&#xff1a;编辑学生信息 4.TreeWidget控件 核心方法 核心信号…

Windows部署NVM并下载多版本Node.js的方法(含删除原有Node的方法)

本文介绍在Windows电脑中&#xff0c;下载、部署NVM&#xff08;node.js version management&#xff09;环境&#xff0c;并基于其安装不同版本的Node.js的方法。 在之前的文章Windows系统下载、部署Node.js与npm环境的方法&#xff08;https://blog.csdn.net/zhebushibiaoshi…

基于STM32设计的粮食仓库(粮仓)环境监测系统

一、前言 1.1 项目开发背景 随着现代农业的发展和粮食储存规模的扩大&#xff0c;粮仓环境的智能化监控需求日益增长。传统的粮仓管理方式通常依赖人工检测和定期巡查&#xff0c;效率低下且容易出现疏漏&#xff0c;无法及时发现潜在问题&#xff0c;可能导致粮食受潮、霉变…

【Linux】--- 进程的等待与替换

进程的等待与替换 一、进程等待1、进程等待的必要性2、获取子进程status3、进程等待的方法&#xff08;1&#xff09;wait&#xff08;&#xff09;函数&#xff08;2&#xff09;waitpid函数 4、多进程创建以及等待的代码模型5、非阻塞接口 轮询 二、进程替换1、替换原理2、替…

Vue2+OpenLayers添加/删除点、点击事件功能实现(提供Gitee源码)

目录 一、案例截图 二、安装OpenLayers库 三、安装Element-UI 四、代码实现 4.1、添加一个点 4.2、删除所有点 4.3、根据经纬度删除点 4.4、给点添加点击事件 4.5、完整代码 五、Gitee源码 一、案例截图 可以新增/删除标记点&#xff0c;点击标记点可以获取到当前标…

HTML中如何保留字符串的空白符和换行符号的效果

有个字符串 储值门店{{thing3.DATA}}\n储值卡号{{character_string1.DATA}}\n储值金额{{amount4.DATA}}\n当前余额{{amount5.DATA}}\n储值时间{{time2.DATA}} &#xff0c; HTML中想要保留 \n的换行效果的有下面3种方法&#xff1a; 1、style 中 设置 white-space: pre-lin…

GB44495-2024 汽车整车信息安全技术要求 - V2X部分前置要求

背景 GB 44495-2024《汽车整车信息安全技术要求》中关于V2X&#xff08;车与外界通信&#xff09;的部分&#xff0c;主要关注于通信安全要求&#xff0c;旨在确保车辆在与外部设备进行数据交互时的信息安全。其测试大致可分为消息层&#xff08;数据无异常&#xff09;、应用…

[PAT 甲级] 1179 Chemical Equation (DFS)

​ 题目翻译&#xff08;GPT&#xff09;&#xff1a; 1179 化学方程式 化学方程式是一种用符号和公式表示化学反应的方法&#xff0c;其中反应物在方程式的左侧&#xff0c;生成物在右侧。例如&#xff1a; CH₄ 2O₂ -> CO₂ 2H₂O 表示反应物为甲烷和氧气&#xff…

android分区和root

线刷包内容&#xff1a; 线刷包是一个完整的android镜像&#xff0c;不但包括android、linux和用户数据&#xff0c;还包括recovery等。当然此图中没有recovery,但是我们可以自己刷入一个。 主要分区 system.img 系统分区&#xff0c;包括linux下主要的二进制程序。 boot.img…

每日一题(五):n个正整数排列,求组合后最大数

目录 一、题目 二、题目分析 &#xff08;一&#xff09;明确需求 背景知识&#xff1a;字符串的比较与连接 1.字符串的比较 2.字符串的连接 (二)分析思路 三、将思路转换为程序 四、总结 一、题目 给定n个正整数a1,a2,……,an对这n个数进行排列&#xff0c;求组合后可以得到…

【STM32-学习笔记-3-】TIM定时器

文章目录 TIM定时器Ⅰ、TIM定时器函数Ⅱ、TIM_TimeBaseInitTypeDef结构体参数①、TIM_ClockDivision②、TIM_CounterMode③、TIM_Period④、TIM_Prescaler⑤、TIM_RepetitionCounter Ⅱ、定时器配置Ⅲ、定时器外部中断NVIC配置 TIM定时器 Ⅰ、TIM定时器函数 // 将定时器寄存器…

【Rust自学】12.2. 读取文件

12.2.0. 写在正文之前 第12章要做一个实例的项目——一个命令行程序。这个程序是一个grep(Global Regular Expression Print)&#xff0c;是一个全局正则搜索和输出的工具。它的功能是在指定的文件中搜索出指定的文字。 这个项目分为这么几步&#xff1a; 接收命令行参数读…

新垂直电商的社交传播策略与AI智能名片2+1链动模式S2B2C商城小程序的应用探索

摘要&#xff1a;随着互联网技术的不断进步和电商行业的快速发展&#xff0c;传统电商模式已难以满足消费者日益增长的个性化和多元化需求。新垂直电商在此背景下应运而生&#xff0c;通过精准定位、用户细分以及深度社交传播策略&#xff0c;实现了用户群体的快速裂变与高效营…

【ORACLE战报】2025.1月OCP | MySQL考试

2025.1月【最新考试成绩出炉】 OCP战报 MySQL 战报 部分学员成绩及证书

九 RK3568 android11 MPU6500

一 MPU6500 内核驱动 1.1 查询设备连接地址 查看原理图, MPU6500 I2C 连接在 I2C4 上, 且中断没有使用 i2c 探测设备地址为 0x68 1.2 驱动源码 drivers/input/sensors/gyro/mpu6500_gyro.c drivers/input/sensors/accel/mpu6500_acc.c 默认 .config 配置编译了 mpu6550 …

Android JecPack组件之LifeCycles 使用详解

一、背景 LifeCycle 是一个可以感知宿主生命周期变化的组件。常见的宿主包括 Activity/Fragment、Service 和 Application。LifeCycle 会持有宿主的生命周期状态的信息&#xff0c;当宿主生命周期发生变化时&#xff0c;会通知监听宿主的观察者。 LifeCycle 的出现主要是为了…