鸿蒙开发实战:仿网易新闻客户端,从零搭建新闻列表与详情页

引言

随着鸿蒙系统(HarmonyOS)的不断普及,越来越多的开发者开始关注鸿蒙应用开发。ArkUI作为鸿蒙的声明式UI框架,提供了丰富的组件和简洁的语法,让开发者能够高效构建跨设备应用。本文将带领大家通过一个完整的实战项目——仿网易新闻客户端,从零开始搭建新闻列表页和详情页,掌握ArkUI的核心用法,并实现页面间跳转与数据传递。

📦 完整项目代码已开源:为了让你能更方便地对照学习和实践,我将本项目的全部源码托管在了 Gitee 上。你可以直接克隆或下载:👉 https://gitee.com/MFliuyangs/news.git 👈

图1:新闻列表页(轮播图+新闻条目)

Snipaste_20260314_120541.jpg
图2:新闻详情页

项目结构

本项目包含三个核心文件:

  • NewsInfo.ets:定义数据模型(IBannerINews)和模拟数据(bannerInfonewsInfo)。
  • NewsCase.ets:新闻列表主页,包含头部搜索栏、轮播图和新闻列表。
  • NewsDetailCase.ets:新闻详情页,展示新闻完整内容。

数据模型与模拟数据

首先定义两个接口,分别用于轮播图项和新闻项:

// NewsInfo.ets
interface INews {
  title: string;
  author: string;
  time: string;
  area: string;
  imagefirst?: string | Resource; // 可选,新闻配图
  msgcount: number;               // 跟帖数
  content: string;
}

interface IBanner {
  id: number;
  image: string | Resource;
  alt: string;
}

接着准备模拟数据,其中新闻内容可以复用同一段文字(实际开发中应从网络获取)。轮播图使用本地图片路径(需提前放入images目录)。

let bannerInfo: Array<IBanner> = [
  { id: 1, image: '/images/xin1.jpg', alt: 'NBA最富老板建球场,最在意的是厕所?' },
  { id: 2, image: '/images/xin2.jpg', alt: '广告:张路&杨健带你足篮彩赢不停' }
];

let newsInfo: Array<INews> = [
  {
    title: '日本加强与欧洲军事互动 专家:仍不放弃“亚洲版北约”构想',
    author: '国际在线',
    time: '2024-11-03 19:23',
    imagefirst: '/images/xw1.jpg',
    msgcount: 2,
    area: '北京',
    content: `下周美国大选对于黄金走势很关键...`  // 省略详细内容
  },
  // ... 更多新闻
];

新闻列表主页(NewsCase.ets)

主页由上到下分为三部分:顶部操作栏、轮播图、新闻列表。

1. 顶部操作栏

使用Row横向布局,包含网易logo、搜索框和联系人按钮。搜索框通过Search组件实现,并自定义占位文本颜色和搜索图标。

Row({ space: 5 }) {
  Image($r('app.media.163_logo')).width(40);
  Search({ placeholder: '输入查询内容' })
    .height(35)
    .layoutWeight(1)
    .backgroundColor(Color.White)
    .placeholderColor("#ffa29f9f")
    .searchIcon({ color: "#ff9d9a9a" });
  Button() {
    Image($r('app.media.ic_public_contacts'))
      .width(25)
      .fillColor(Color.White)
      .aspectRatio(1);
  }
  .opacity(0.4)
  .backgroundColor('#000000')
  .padding(5);
}
.padding(5)
.backgroundColor(Color.Red)
.width('100%');

2. 轮播图(Swiper)

使用Swiper组件自动轮播图片,通过ForEach遍历bannerInfo数组动态生成。设置自动播放、间隔1秒、无限循环等属性。

Swiper(this.swiperController) {
  ForEach(this.bannerInfo, (item: IBanner) => {
    Image(item.image)
      .width('100%')
      .alt($r('app.media.xin1'));
  }, (item: IBanner): string => String(item.id));
}
.autoPlay(true)
.interval(1000)
.loop(true)
.duration(1);

3. 新闻列表(List)

新闻列表使用List组件,每个列表项为ListItem,内部采用Row横向布局,左侧是标题、作者、跟帖数,右侧是缩略图。关键点:

  • 标题最多显示两行,超出省略号(maxLines(2) + textOverflow)。
  • 跟帖数超过1万时显示为“X万”格式。
  • 点击列表项通过router.pushUrl跳转到详情页,并将当前新闻对象作为参数传递。
List() {
  ForEach(this.newsInfo, (item: INews) => {
    ListItem() {
      Row({ space: 5 }) {
        Column() {
          Text(item.title)
            .fontSize(20)
            .fontWeight(600)
            .maxLines(2)
            .textOverflow({ overflow: TextOverflow.Ellipsis });
          Row() {
            Text(item.author).margin({ right: 10 }).fontColor('#999');
            Text(item.msgcount < 10000 ? 
                 String(item.msgcount) : (item.msgcount / 10000).toFixed(1) + '万')
              .fontColor('#999');
            Text('跟帖').fontColor('#999');
          }
          .padding(5)
          .width('100%');
        }
        .height(100)
        .justifyContent(FlexAlign.SpaceBetween)
        .layoutWeight(1);

        Image(item.imagefirst)
          .width(100)
          .alt($r('app.media.xin1'))
          .aspectRatio(1);
      }
      .width('100%')
      .border({ width: { bottom: 1 } })
      .borderColor('#eee')
      .padding(10);
    }
    .onClick(() => {
      router.pushUrl({
        url: 'pages/NewsDetailCase',
        params: item
      });
    });
  });
}
.width('100%');

新闻详情页(NewsDetailCase.ets)

详情页接收主页传递的新闻对象,并展示完整内容。

1. 页面生命周期获取参数

onPageShow中通过router.getParams()获取参数并赋值给状态变量news

@State news: INews = {} as INews;

onPageShow(): void {
  this.news = router.getParams() as INews;
}

2. 布局结构

使用Navigation组件作为容器,设置标题模式为Mini,标题为新闻标题。顶部显示作者、时间、地区,中间显示新闻图片(如果有)和滚动内容。

Navigation() {
  Column() {
    // 头部作者信息
    Row() {
      Image($r('app.media.news_logo_img')).width(32);
      Column() {
        Text(this.news.author);
        Text(`${this.news.time}·${this.news.area}`)
          .fontSize(10)
          .fontColor('#999');
      }
      .layoutWeight(1)
      .alignItems(HorizontalAlign.Start);
    }
    .width('100%')
    .padding(10);

    // 新闻图片(如果有)
    if (this.news.imagefirst) {
      Image(this.news.imagefirst)
        .width('95%');
    }

    // 新闻内容滚动区域
    Scroll() {
      Text(this.news.content);
    }
    .margin({ top: 10 })
    .layoutWeight(1);
  }
  .height('100%')
  .width('100%');
}
.titleMode(NavigationTitleMode.Mini)
.title(this.news.title);

3. 细节优化

  • 评论按钮功能暂时注释,可后续扩展。
  • 内容区域使用Scroll组件,确保长内容可滚动。
  • 图片路径处理:使用$r引用资源或直接字符串路径,需确保资源存在。

运行效果与测试

🔧 快速开始

如果你想直接运行这个项目,可以按照以下步骤操作:

  1. 下载开发工具:访问华为开发者官网,下载并安装最新版本的 DevEco Studio
  2. 配置环境:在 DevEco Studio 中设置好 HarmonyOS SDK 的路径。
  3. 克隆项目:打开终端,执行以下命令将项目克隆到本地:
    git clone https://gitee.com/MFliuyangs/news.git
    
  4. 导入并运行:在 DevEco Studio 中打开刚克隆的项目文件夹,连接模拟器或真机,点击运行按钮即可看到效果。

Snipaste_20260314_120541.jpg
图3:列表页实际运行效果

Snipaste_20260314_120559.jpg

开发心得与优化方向

  1. 声明式UI的便利:ArkUI的声明式语法让界面与状态绑定,数据变化自动更新UI,开发效率很高。
  2. 组件化思维:将轮播图、列表项等拆分为独立组件,便于复用和维护。
  3. 路由传参router.pushUrl传递对象时,需确保对象可序列化(本例中INews满足要求)。

结语

通过这个仿网易新闻客户端的实战,我们学习了ArkUI中常用的SwiperListNavigation等组件,掌握了页面路由和数据传递的方法。希望本文能帮助鸿蒙开发者快速入门,并激发更多创意。完整代码已放在 Gitee仓库 中,欢迎 Star 和 Fork,如果你有任何问题或建议,也欢迎在评论区交流讨论!

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐