前言

随着鸿蒙next星河版系统的公布,越来越多的大厂都纷纷下场加入鸿蒙应用开发中,作为第一批响应鸿蒙原生开发的应用,小红书的市场份额也不言而喻,现阶段我们大部分开发对鸿蒙的基础知识已经掌握,那么我们在开发中要自己实现小红书的功能要如何去做呢?

 #HarmonyOS NEXT体验官#HarmoneyOS NEXT应用开发实战《仿xhs首页列表与详情》_数据

大部分情况如下所示

1. 打开百度

2. 输入鸿蒙仿小红书

3. cccv提交代码一气呵成

可今天,看了我这篇文章,你自己就是一个团队,分分钟拿下某书,为你的大牛之路添砖加瓦。。。

今天我们就在HamoneyOS中先实现一个小红书首页和详情。

效果介绍

首先就是我们的首页效果

 #HarmonyOS NEXT体验官#HarmoneyOS NEXT应用开发实战《仿xhs首页列表与详情》_数据_02

1首页分为头部分类

2二级分类

3底部功能模块


当我们点击列表中的某一条数据,跳转到详情页(如下图)

 #HarmonyOS NEXT体验官#HarmoneyOS NEXT应用开发实战《仿xhs首页列表与详情》_Text_03


1详情页分为顶部用户信息展示模块2图文展示

3底部点赞发言模块



那我们的需求已经很明确了,接下来我们来讲解如何通过代码来实现我们对应页面的效果

 #HarmonyOS NEXT体验官#HarmoneyOS NEXT应用开发实战《仿xhs首页列表与详情》_Image_04


代码实现

首页的头部分类跟二级分类,都要用到ArkUi的Tabs组件

首先我们需要先定义好tabs需要显示的数据我们通过创建多个tabcontent 然后在tabBar中放入页签

然后我们需要给tabs创建一个自定义的页签,来实现我们点击时组件的切换效果

 #HarmonyOS NEXT体验官#HarmoneyOS NEXT应用开发实战《仿xhs首页列表与详情》_Image_05

 #HarmonyOS NEXT体验官#HarmoneyOS NEXT应用开发实战《仿xhs首页列表与详情》_数据_06


@Builder TabBuilder(index: number, name: string) {
    Column() {
      Text(name)
        .fontColor(this.currIndex === index ? this.selectedFontColor : this.fontColor)
        .fontSize(this.currIndex === index ?16:14)
        .fontWeight(this.currIndex === index ? 500 : 400)
        .lineHeight(22)
        .margin({ top: 17, bottom: 7 })
      Divider()
        .lineCap(LineCapStyle.Round)
        .width(30)
        .strokeWidth(2)
        .color(Color.Red)
        .opacity(this.currIndex === index ? 1 : 0)
    }
    .padding({left:10,right:10})
  }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

之后因为我们的列表是一行两列所以我们还需要使用Grid 组件来实现列表

我们用@Builder 来声明,方便我们自由引用(列表展示如下)


 #HarmonyOS NEXT体验官#HarmoneyOS NEXT应用开发实战《仿xhs首页列表与详情》_数据_07

@Builder
  buildList() {
    Grid() {
      ForEach(this.channelList, (item: HomeBean) => {
        GridItem(){
          this.NewsItem(item)

        }
      })
    }
    .padding(10)
    .columnsGap(10)
    .rowsGap(10)
    .columnsTemplate('1fr 1fr')
    .height('100%')
    .width('100%')
    .align(Alignment.TopStart)
  }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

因为grid 组件需要显示多条,现在开始定义一条的样式实现如下

(分别有图片,头像,昵称,icon ,点赞数)

 #HarmonyOS NEXT体验官#HarmoneyOS NEXT应用开发实战《仿xhs首页列表与详情》_数据_08

@Builder NewsItem(item:HomeBean){
    Column(){
      Image(item.imgUrl)
        .objectFit(ImageFit.Fill)
        .height(190)
        .width('100%')
        .interpolation(ImageInterpolation.High)

        .borderRadius({topLeft:5,topRight:5})
      Text(item.title).fontSize(12).fontWeight(FontWeight.Bold).margin({top:8,left:5})
        .textOverflow({overflow:TextOverflow.Ellipsis})
        .maxLines(2)
        .fontColor("#333333")


      Row(){
        Image(item.icon).width(20)
          .height(20).borderRadius(10)
          .interpolation(ImageInterpolation.High)

        Text(item.name).fontSize(12).fontColor("#999999").margin({left:5})
        Blank()
        Image($r('app.media.xihuan'))
          .width(15)
          .height(15)
          .interpolation(ImageInterpolation.High)

        Text(String(item.like)).fontSize(12)
          .fontColor("#999999")
      }
      .margin({top:10})
      .alignItems(VerticalAlign.Center)
      .justifyContent(FlexAlign.SpaceBetween)
      .width('100%')
    }
    .backgroundColor(Color.White)
    .borderRadius(10)
    .width('100%')
    .alignItems(HorizontalAlign.Start)
    .justifyContent(FlexAlign.Start)
    .onClick(()=>{
      //点击事件处理
      router.pushUrl({url:'pages/DetailsPage',params:{
        data:JSON.stringify(item)
      }})
    })
  }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.

之后我们把定义的两个布局跟tabs 进行结合

Tabs({ barPosition: BarPosition.Start, controller: this.controller }) {
        TabContent() {
          Column(){
                  this.buildList()
                }
                .layoutWeight(1)
                .backgroundColor("#F9F9F9")
                .width('100%')
                .height('100%')
        }.tabBar(this.TabBuilder(0, 'green'))
      }
      .vertical(false)
      .barMode(BarMode.Fixed)
      .barWidth(360)
      .barHeight(56)
      .animationDuration(400)
      .onChange((index: number) => {
        this.currentIndex = index
      })
      .width(360)
      .height(296)
      .margin({ top: 52 })
      .backgroundColor('#F1F3F5')
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.

这样我们的页面框架就搭好了(展示如下)

 #HarmonyOS NEXT体验官#HarmoneyOS NEXT应用开发实战《仿xhs首页列表与详情》_数据_09

现在我们创建DataModel 开始填充我们页面框架需要展示的数据,数据内容可以自己根据需求制定


先定义一个实体类

export class  HomeBean {
  imgUrl:string
  title:string
  icon:string
  name:string
  like:string
  msg:string

  constructor( imgUrl:string,
  title:string,
  icon:string,
  name:string,
  like:string,
               msg:string) {
    this.imgUrl=imgUrl
    this.title=title
    this.icon=icon
    this.name=name
    this.like=like
    this.msg=msg
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.

然后我们创建DataModel 数据源,填充数据

import { HomeBean } from '../entity/HomeBean'

export class  DataModel {
  getHome():Array<HomeBean>{
    let list:HomeBean[]=[
      new HomeBean(
        "https://tse3-mm.cn.bing.net/th/id/OIP-C.ZgeX3Yk1FFFuPxKZmNgoZwHaI0?w=146&h=180&c=7&r=0&o=5&dpr=2&pid=1.7"
      ,"彩色日记",
      "https://tse3-mm.cn.bing.net/th/id/OIP-C.Fyq_wIdHP0_3aaHJuz1w_wAAAA?w=140&h=203&c=7&r=0&o=5&dpr=2&pid=1.7"
      ,"南北芝麻糊",

      "1805","使用彩铅、水彩、马克笔等画材,在日记本上不仅仅书写文字,还配以当日心情、天气或重要事件相关的彩色插画。这样,每一天的记录都成为了一幅独一无二的艺术作品,颜色反映了当天的情绪和体验。"),
      new HomeBean(
        "https://tse2-mm.cn.bing.net/th/id/OIP-C.myAvQCC58qS6DDa6lY_x4QHaHm?w=217&h=220&c=7&r=0&o=5&dpr=2&pid=1.7"
        ,"一定要看到最后,古董鉴赏",
        "https://tse3-mm.cn.bing.net/th/id/OIP-C.ThlIZCylEwsmbz2ZGAYglAAAAA?w=199&h=199&c=7&r=0&o=5&dpr=2&pid=1.7"
        ,"类哥累不累",
        "988","鉴赏古瓷:看这一篇就够了. 中国古瓷器的历史悠久,青瓷的制作可追溯到两千多年前的西周时期。. 在古瓷器制作过程中包括选料、加工、制胎、上釉等多道工序。")
    ]

    return list
  }


 
}
export default new DataModel()

接下来只需要在Page页面中引入我们定义的数据源
 
 private  channelList:HomeBean[]=DataModel.getHome()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.

这样我们的页面就可以展示数据了

 #HarmonyOS NEXT体验官#HarmoneyOS NEXT应用开发实战《仿xhs首页列表与详情》_Text_10

详情页面我们只需要在列表条目上添加一个点击事件,事件触发的时候把数据传过去就可以了(代码实现如下)

我们通过router ->pushUrl ->params 传递参数过去,定义key为data 
 .onClick(()=>{
      //点击事件处理
      router.pushUrl({url:'详情页面路由',params:{
        data:JSON.stringify(item)
      }})

既然涉及到了跳转,那我们就需要创建一个新的详情页面,然后在router中填写相应的路由


在详情页面我们用data的key去接收数据
先定义我们接收数据的实体类型的参数
  @State dataDetail:HomeBean=null
然后接收数据,在组件的生命周期中赋值给他
aboutToAppear(){
    let order:string= router.getParams()['data']
    let data:HomeBean= JSON.parse(order)
    this.dataDetail=data
  }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

接下来我们添加头部模块并填充图文数据



效果如下

 #HarmonyOS NEXT体验官#HarmoneyOS NEXT应用开发实战《仿xhs首页列表与详情》_Image_11

Column() {
        Row(){
          Image($r('app.media.back'))
            .width(25)
            .height(25)
            .onClick(()=>{
              router.back()
            })
          Image(this.dataDetail.icon)
            .height(30)
            .width(30)
            .borderRadius(20)
            .margin({left:10})
            .interpolation(ImageInterpolation.High)

          Text(this.dataDetail.name)
            .margin({left:10})

          Blank()
          Text("关注")
            .border({width:1,color:Color.Red,radius:20})
            .padding({left:7,right:7,top:3,bottom:3})
            .margin({right:10})
            .fontSize(14)
            .fontColor(Color.Red)
          Image($r('app.media.fenxiang'))
            .width(25)
            .height(25)
            .margin({right:25})
            .interpolation(ImageInterpolation.High)
        }
        .width('100%')
        .margin({top:10})

        Image(this.dataDetail.imgUrl)
          .height(300)
          .width('100%')
          .margin({top:20})
        Text(this.dataDetail.title)
          .margin({left:15,top:10})
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
        Text(this.dataDetail.msg)
          .fontSize(16)
          .margin({top:15})
          .padding(10)


      }
      .layoutWeight(1)
      .alignItems(HorizontalAlign.Start)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.

好的,到这里我们的xhs首页,详情页面的效果就实现了,快去试一试吧!