赞
踩
本文介绍一个基于鸿蒙ArkTS开发的App,是一个包含轮播图、文章列表和 Web 页面等功能的多页面应用。
本文主要内容包括:
App底部是一个TabBar,点击TabBar可以切换上面的页面。共包含两个页面,一个是“首页” ,另一个是“空白页”。
App顶部是一个Banner,也叫轮播图,点击轮播图可以跳转到对应的详情页面。
轮播图下方是一个List组件,点击其中某一项可以跳转详情页面。
使用系统组件@ohos.web.webview 显示网页。同时,此详情页面顶部有一个标题栏,用于显示返回键和标题。
首先实现主界面,包含一个TabBar和上面的两个页面,以下是主界面代码:
- import Constants from '../Constants/Constants'
- import Home from './Home';
- import EmptyPage from './EmptyPage';
- @Entry
- @Component
- struct Index {
- @State currentTabIndex: number = 0;
- tabsController: TabsController;
- aboutToAppear(){
- this.tabsController = new TabsController();
- }
- @Builder TabBuilder(title: string, index: number, icon: Resource) {
- Column() {
- Image(icon)
- .width($r('app.float.mainPage_baseTab_size'))
- .height($r('app.float.mainPage_baseTab_size'))
- .fillColor(this.getTabBarColor(index))
- Text(title)
- .margin({ top: $r('app.float.mainPage_baseTab_top') })
- .fontSize($r('app.float.main_tab_fontSize'))
- .fontColor(this.getTabBarColor(index))
- }
- .justifyContent(FlexAlign.Center)
- .height($r('app.float.mainPage_barHeight'))
- .width(Constants.FULL_PARENT)
- .onClick(() => {
- this.currentTabIndex = index;
- this.tabsController.changeIndex(this.currentTabIndex)
- })
- }
-
- // 获取选项卡栏颜色
- getTabBarColor(index: number){
- if(index == this.currentTabIndex){
- return Color.Blue;
- }else{
- return Color.Gray;
- }
- }
-
- build() {
- Tabs({
- barPosition: BarPosition.End,
- controller: this.tabsController
- }) {
- // 首页
- TabContent() {
- Home()
- }
- .padding({ left: $r('app.float.mainPage_padding'), right: $r('app.float.mainPage_padding') })
- .backgroundColor($r('app.color.mainPage_backgroundColor'))
- .tabBar(this.TabBuilder(Constants.HOME_TITLE, Constants.HOME_TAB_INDEX
- , $r('app.media.ic_bottom_home')))
-
- // 项目
- TabContent() {
- EmptyPage()
- }
- .padding({ left: $r('app.float.mainPage_padding'), right: $r('app.float.mainPage_padding') })
- .backgroundColor($r('app.color.mainPage_backgroundColor'))
- .tabBar(this.TabBuilder(Constants.EMPTY_TITLE, Constants.EMPTY_TAB_INDEX
- , $r('app.media.ic_bottom_empty')))
- }
- .width(Constants.FULL_PARENT)
- .backgroundColor(Color.White)
- .barHeight($r('app.float.mainPage_barHeight'))
- .barMode(BarMode.Fixed)
- .onChange((index: number) => {
- this.currentTabIndex = index;
- })
- }
- }

本文主要实现的就是首页,用竖向列包含了Banner组件和ArticleList组件,代码如下:
- @Component
- export default struct Home {
- build() {
- Column() {
- Banner();
- ArticleList();
- }
- }
- }
其中Banner组件代码如下,代码中有具体实现的解释:
- // 标记为组件
- @Component
- // 导出名为 Banner 的结构体
- export default struct Banner {
- // Swiper 控制器
- swiperController: SwiperController = new SwiperController();
- // 轮播图数据
- @State bannerData: HomeBannerItemBean[] = [];
-
- // 生命周期钩子,在即将显示时调用
- aboutToAppear() {
- // 获取轮播图数据
- this.getData();
- }
-
- // 异步获取轮播图数据
- async getData(){
- await HomeViewModel.getHomeBanner(Constants.GET_HOME_BANNER).then((data: HomeBannerItemBean[]) => {
- // 将获取到的数据赋值给轮播图数据
- this.bannerData = data;
- }).catch((err: string | Resource) => {
- // 如果发生错误,显示提示消息
- promptAction.showToast({
- message: err,
- duration: Constants.ANIMATION_DURATION
- });
- });
- }
-
- // 构建界面
- build() {
- // 垂直排列的列
- Column() {
- // 如果有轮播图数据且数据长度大于 0
- if(this.bannerData && this.bannerData.length > 0){
- // 使用 Swiper 组件创建轮播图
- Swiper(this.swiperController) {
- // 遍历轮播图数据
- ForEach(this.bannerData, (banner: HomeBannerItemBean) => {
- // 显示图片,并设置圆角和点击事件
- Image(banner.imagePath).borderRadius($r('app.float.home_swiper_borderRadius')).onClick(() => {
- // 点击事件:跳转到 Web 页面,并传递标题和链接参数
- router.pushUrl({
- url: 'pages/WebPage',
- params: {
- title: banner.title,
- src: banner.url
- }
- }, router.RouterMode.Single)
- })
- }, (img: Resource) => JSON.stringify(img.id))
- }
- // 设置轮播图的外边距、自动播放、宽度和高度
- .margin({top: $r('app.float.home_swiper_margin')})
- .autoPlay(true)
- .width(Constants.FULL_PARENT)
- .height(200)
- }
- }
- }
- }

那么在Banner组件下方的ArticleList组件,代码如下:
- // 标记为组件
- @Component
- // 导出名为 ArticleList 的结构体
- export default struct ArticleList {
- // 是否还有更多数据
- hasMore: boolean = true;
- // 当前页码
- currentPage: number = 0;
- // 每页数据量
- pageSize: number = 30;
- // 文章数据数组
- @State articleData: ArticleItemData[] = [];
- // 需绑定列表或宫格组件的滚动控制器
- private scroller: Scroller = new Scroller();
-
- // 生命周期钩子,在即将显示时调用
- aboutToAppear() {
- // 获取文章列表数据,参数为 true 表示重置数据
- this.getArticleList(true);
- }
-
- // @Builder 修饰的私有方法,用于创建列表视图
- @Builder
- private getListView() {
- // 使用 List 组件创建列表
- List({ space: 10, scroller: this.scroller }) {
- // 遍历文章数据
- ForEach(this.articleData, (item: ArticleItemData) => {
- // 使用 ListItem 创建列表项
- ListItem() {
- // 使用 Flex 创建布局
- Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.SpaceBetween, }) {
- // 作者和发布时间
- Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceBetween, }) {
- Text(item.author)
- .fontSize(13)
- Text(Util.dateTime(item.publishTime))
- .fontSize(13)
- }.margin({ top: 10, left: 30, right: 30 })
-
- // 文章标题
- Text(item.title)
- .width('100%')
- .fontSize(20)
- .textAlign(TextAlign.Center)
- .fontWeight(FontWeight.Bold)
- .maxLines(1)
- .textOverflow({ overflow: TextOverflow.Ellipsis })
- .margin({ left: 10, right: 10 })
-
- // 文章分类
- Text(item.chapterName)
- .fontSize(13)
- .textAlign(TextAlign.Start)
- .width('100%')
- .margin({ left: 30, bottom: 10 })
- }.borderRadius($r('app.float.home_list_borderRadius'))
- .backgroundColor(Color.White)
- }.onClick(() => {
- // 点击列表项跳转到 Web 页面,传递标题和链接参数
- router.pushUrl({
- url: 'pages/WebPage',
- params: {
- title: item.title,
- src: item.link
- }
- }, router.RouterMode.Single)
- })
- })
- }
- // 设置列表的圆角
- .borderRadius($r('app.float.home_list_borderRadius'))
- // .divider({ strokeWidth: 1, color: 0x222222 })
- // 设置列表的边缘效果为无效果
- .edgeEffect(EdgeEffect.None)
- // 设置列表宽度和高度为100%
- .width('100%')
- .height('100%')
- }
-
- // 异步获取文章列表数据
- async getArticleList(reset: boolean) {
- await HomeViewModel.getHomeArticleList(this.currentPage, this.pageSize, Constants.GET_HOME_ARTICLE_LIST)
- .then((data: ArticleDataBean) => {
- // 判断是否还有更多数据
- if (data.curPage < data.pageCount) {
- this.currentPage++;
- this.hasMore = true;
- } else {
- this.hasMore = false;
- }
- // 根据参数判断是否重置数据
- if (reset) {
- this.articleData = data.datas;
- } else {
- this.articleData = this.articleData.concat(data.datas);
- }
- }).catch((err: string | Resource) => {
- // 显示错误提示
- promptAction.showToast({ message: err });
- })
- }
-
- // 构建界面
- build() {
- // 使用 Column 组件创建垂直布局
- Column() {
- // 使用 PullToRefresh 组件实现下拉刷新和上拉加载
- PullToRefresh({
- customRefresh: null,
- customLoad: null,
- data: $articleData, // 数据源数组
- scroller: this.scroller, // 控制器,负责关闭下拉和上拉
- customList: () => {
- // 调用 getListView 方法创建列表视图
- this.getListView();
- },
- onRefresh: () => {
- return new Promise<string>((resolve, reject) => {
- // 下拉刷新成功后解析数据,重新获取文章列表数据
- resolve('下拉刷新成功')
- this.getArticleList(true);
- });
- },
- onLoadMore: () => {
- // 上拉加载成功后解析数据,继续获取更多文章列表数据
- return new Promise<string>((resolve, reject) => {
- resolve('上拉加载成功')
- this.getArticleList(false);
- });
- }
- })
- }.backgroundColor("#efefef") // 设置背景颜色
- }
- }

这个文章列表组件,使用了 PullToRefresh 组件和 List 组件展示通过网络获取的文章列表数据,并且点击其中每一项都可以跳转详情页面,使用到的系统方法是router.pushUrl。
其中网络请求代码如下:
- /**
- * 发起 HTTP GET 请求的函数
- * @param url 请求的 URL 地址
- * @param extraData 额外的请求数据,可选参数
- * @returns 返回 Promise 对象,包含 ResponseResult 数据
- */
- export function httpRequestGet(url: string, extraData?: Record<string, any>): Promise<ResponseResult> {
- // 创建 HTTP 请求实例
- let httpRequest = http.createHttp();
-
- // 发起 HTTP GET 请求
- let responseResult = httpRequest.request(url, {
- method: http.RequestMethod.GET,
- readTimeout: Constants.HTTP_READ_TIMEOUT,
- header: {
- 'Content-Type': ContentType.JSON
- },
- connectTimeout: Constants.HTTP_READ_TIMEOUT,
- extraData: extraData || {} // 使用 extraData 参数,如果不存在则传递一个空对象
- });
-
- // 创建用于存储响应数据的对象
- let serverData: ResponseResult = new ResponseResult();
-
- // 处理返回的数据并返回结果
- return responseResult.then((value: http.HttpResponse) => {
- // 检查 HTTP 响应码是否为成功状态(200)
- if (value.responseCode === Constants.HTTP_CODE_200) {
- // 解析返回的数据
- let result = `${value.result}`;
- let resultJson: ResponseResult = JSON.parse(result);
-
- // 检查服务器返回的错误码是否为成功状态
- if (resultJson.errorCode === Constants.SERVER_CODE_SUCCESS) {
- // 将返回的数据赋值给 serverData 对象
- serverData.data = resultJson.data;
- }
- // 将服务器返回的错误码和错误消息赋值给 serverData 对象
- serverData.errorCode = resultJson.errorCode;
- serverData.errorMsg = resultJson.errorMsg;
- } else {
- // 设置错误消息,包含 HTTP 错误码
- serverData.errorMsg = `${$r('app.string.http_error_message')}&${value.responseCode}`;
- }
- // 返回处理后的 serverData 对象
- return serverData;
- }).catch((err) => {
- // 捕获异常,打印错误信息,并设置错误消息
- console.log("error:" + JSON.stringify(err));
- serverData.errorMsg = $r('app.string.http_error_message');
- // 返回处理后的 serverData 对象
- return serverData;
- });
- }

详情页面是通过webview来展示网页实现的,代码如下:
- // 标记为入口
- @Entry
- // 标记为组件
- @Component
- // Web 页面结构体
- struct WebPage {
- // 从路由获取参数中的 'src',并存储到状态中
- @State src: string = router.getParams()?.['src'];
- // 从路由获取参数中的 'title',并存储到状态中
- @State title: string = router.getParams()?.['title'];
-
- // Web 页面控制器
- controller: web_webview.WebviewController = new web_webview.WebviewController();
-
- // 构建界面
- build() {
- // 使用 Column 组件创建垂直布局
- Column() {
- // 页面标题组件
- PageTitle({ titleName: this.title })
-
- // 分隔线
- Divider()
- .strokeWidth('1px')
- .color($r('sys.color.ohos_id_color_list_separator'))
-
- // Web 组件,加载指定的网址,并使用控制器进行交互
- Web({
- src: this.src, controller: this.controller
- }).javaScriptAccess(true)
- }
- }
- }
-
- // 页面标题组件结构体
- @Component
- struct PageTitle {
- // 标题名称
- private titleName: string
-
- // 构建界面
- build() {
- // 使用 Row 组件创建水平布局
- Row() {
- // 返回按钮图标
- Image($r('app.media.back'))
- .width(20)
- .height(20)
- .onClick(() => {
- // 点击返回按钮,触发路由返回操作
- router.back()
- })
-
- // 标题文本
- Text(this.titleName)
- .fontSize(Constants.PAGE_TITLE_TEXT_SIZE)
- .width(Constants.PAGE_TITLE_TEXT_WIDTH)
- .maxLines(Constants.PAGE_TITLE_TEXT_MAX_LINES)
- .textOverflow({ overflow: TextOverflow.Ellipsis })
- .margin({ left: 20 })
- }
- // 设置整体内边距
- .padding(12)
- // 设置整体宽度为100%
- .width('100%')
- }
- }

WanAndroid: 基于鸿蒙ArkTS语言实现的WanAndroid App
如果觉得本文不错的话,帮忙点个赞吧~感谢~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。