当前位置: 首页 > article >正文

鸿蒙HarmonyOS评论功能小demo

评论页面小demo

效果展示

img

1.拆解组件,分层搭建

我们将整个评论页面拆解为三个组件,分别是头部导航,评论项,回复三个部分,然后统一在index界面导入

image-20250304150652225

2.头部导航界面搭建

image-20250304151026576

@Preview
@Component
struct HmNavBar {
  // 属性:是可以被传递值进行替换的
  build() {
    Stack({ alignContent: Alignment.Start }) {
      Row() {
        Image($r('sys.media.ohos_ic_compnent_titlebar_back'))
          .width('100%')
          .aspectRatio(1)
      }.width(24)
      .padding(4)
      .borderRadius(12)
      .backgroundColor('#f5f7f8')


      Text('评论回复')//先设置占页面的100%  然后在居中对齐
        .width('100%')
        .textAlign(TextAlign.Center)
    }
    .width('100%')
    .padding(20)
  }
}

export { HmNavBar }
  • 上述UI界面搭建很简单,但要注意一点就是在有了返回按钮的情况下如何让评论回复在整行居中,我们可以采用Stack布局,或者是在右边也放置一个宽度为24的容器

3.评论项搭建

image-20250304151409576

@Preview
@Component
struct HmReplay {
  build() {
    Row({ space: 8 }) {
      Image($r('app.media.Cover1'))
        .width(60)
        .borderRadius(30)
      Column({ space: 5 }) {
        Text('遇到困难睡大觉')
          .fontSize(18)
          .fontWeight(700)
        Text('你已经是一个成熟的评论了要学会自己打破零回复!')
          .fontSize(18)

        Row() {
          Row() {
            Text('10-21.IP 属地安徽')
              .fontColor('#ffcfcfcf')
          }

          Row({ space: 5 }) {
            Image($r('app.media.love'))
              .width(24)
              .aspectRatio(1)
            Text('100')
              .fontColor('#ffcfcfcf')
          }
        }.width('100%')
        .justifyContent(FlexAlign.SpaceBetween)
      }.layoutWeight(1)
      .alignItems(HorizontalAlign.Start)

    }.width('100%')
    .padding(20)
    .height(120)
    .alignItems(VerticalAlign.Top)

  }
}

export { HmReplay }

4.评论列表搭建

4.1.1分割线+回复 部分

    Row() {
        Text('回复 (7)')
      }.padding(12)
      .border({
        width: {
          top: 6
        },
        color: 'rgb(246,246,246)'
      })
      .width('100%')

4.1.2 评论列表

1.导入对应的数据结构
@State commentList: ReplyItemModel[] = [
    new ReplyItemModel({
      id: 1,
      avatar: 'https://picx.zhimg.com/027729d02bdf060e24973c3726fea9da_l.jpg?source=06d4cd63',
      author: '偏执狂-妄想家',
      content: '更何况还分到一个摩洛哥[惊喜]',
      time: '11-30',
      area: '海南',
      likeNum: 34,
      likeFlag: false
    }),
    new ReplyItemModel({
      id: 2,
      avatar: 'https://pic1.zhimg.com/v2-5a3f5190369ae59c12bee33abfe0c5cc_xl.jpg?source=32738c0c',
      author: 'William',
      content: '当年希腊可是把1:0发挥到极致了',
      time: '11-29',
      area: '北京',
      likeNum: 58,
      likeFlag: false
    }),
    new ReplyItemModel({
      id: 3,
      avatar: 'https://picx.zhimg.com/v2-e6f4605c16e4378572a96dad7eaaf2b0_l.jpg?source=06d4cd63',
      author: 'Andy Garcia',
      content: '欧洲杯其实16队球队打正赛已经差不多,24队打正赛意味着正赛阶段在小组赛一样有弱队。',
      time: '11-28',
      area: '上海',
      likeNum: 10,
      likeFlag: false
    }),
    new ReplyItemModel({
      id: 4,
      avatar: 'https://picx.zhimg.com/v2-53e7cf84228e26f419d924c2bf8d5d70_l.jpg?source=06d4cd63',
      author: '正宗好鱼头',
      content: '确实眼红啊,亚洲就没这种球队,让中国队刷',
      time: '11-27',
      area: '香港',
      likeNum: 139,
      likeFlag: false
    }),
    new ReplyItemModel({
      id: 5,
      avatar: 'https://pic1.zhimg.com/v2-eeddfaae049df2a407ff37540894c8ce_l.jpg?source=06d4cd63',
      author: '柱子哥',
      content: '我是支持扩大的,亚洲杯欧洲杯扩到32队,世界杯扩到64队才是好的,世界上有超过200支队伍,欧洲区55支队伍,亚洲区47支队伍,即使如此也就六成出现率',
      time: '11-27',
      area: '旧金山',
      likeNum: 29,
      likeFlag: false
    }),
    new ReplyItemModel({
      id: 6,
      avatar: 'https://picx.zhimg.com/v2-fab3da929232ae911e92bf8137d11f3a_l.jpg?source=06d4cd63',
      author: '飞轩逸',
      content: '禁止欧洲杯扩军之前,应该先禁止世界杯扩军,或者至少把亚洲名额一半给欧洲。',
      time: '11-26',
      area: '里约',
      likeNum: 100,
      likeFlag: false
    })
  ]
//先定义一个接口 然后可以使用接口转换工具转换成对应的类
export interface ReplyItem {
  avatar: ResourceStr // 头像
  author: string // 作者
  id: number // 评论的id
  content: string // 评论内容
  time: string // 发表时间
  area: string // 地区
  likeNum: number // 点赞数量
  likeFlag: boolean | null // 当前用户是否点过赞
}

export class ReplyItemModel implements ReplyItem {
  avatar: ResourceStr = ''
  author: string = ''
  id: number = 0
  content: string = ''
  time: string = ''
  area: string = ''
  likeNum: number = 0
  likeFlag: boolean | null = null

  constructor(model: ReplyItem) {
    this.avatar = model.avatar
    this.author = model.author
    this.id = model.id
    this.content = model.content
    this.time = model.time
    this.area = model.area
    this.likeNum = model.likeNum
    this.likeFlag = model.likeFlag
  }
}

4.搭建评论列表界面
      List() {
        ForEach(this.commentList, (item: ReplyItemModel) => {
          ListItem() {
            HmCommentItem({
              commentInfo: item,
              //但凡传函数吧必须用箭头函数包裹!
              changeLike:(id:number)=>{
                this.changeLike(id)
              }
            })
          }

        })
      }.layoutWeight(1)
  • 这里需要注意几点
  1. List里面必须放置ListItem()
  2. 评论列表的高度可以给一个自适应,这样可以让列列表超出屏幕的高度时实现自适应

5.点赞逻辑的实现

实现任务:当我们点击爱心或者点赞的时候,点赞数量+1,爱心变位红色,当我们再次点击,点赞由原来的点赞变为取消点赞,爱心的颜色变为灰色,点赞的数量-1

代码层面分析:由于我们显示的数据是由主界面传到子界面的,所以我们需要在父界面定义一个方法,传递到子面去,在子界面去调用这个方法,所以在子界面需要有一个接受的方法

5.1.1 子界面接收的方法

  changeLike:(id:number)=>void = ()=> {

  }

5.1.2 点赞业务逻辑的实现

  //点赞逻辑处理
  changeLike(id:number){
    //遍历数组  对commentlist数组中的每一个元素item进行迭代
    const index = this.commentList.findIndex(item =>item.id === id)
    //分支处理主评论和回复评论点赞状态
    if(index < 0){//处理主评论
      if(this.comment.likeFlag){//已经点赞
        this.comment.likeNum -- //点赞数量--
      }else {//未点赞
        //点赞数量++
        this.comment.likeNum++
      }

      this.comment.likeFlag = !this.comment.likeFlag
    }else{//处理回复评论   找到回复列表中的某一个子评论
      //返回第一次匹配元素的数组索引(0~N)
      if(this.commentList[index].likeFlag){
        this.commentList[index].likeNum--
      }else {
        this.commentList[index].likeNum++
      }
      this.commentList[index].likeFlag = !this.commentList[index].likeFlag
   //@State修饰的数据只能监听到第一层或者本身  需要new一下在使用
      this.commentList[index] = new ReplyItemModel(this.commentList[index])
      // this.commentList.splice(index,1,this.commentList[index])
    }

5.1.3父界面进行传值

image-20250304214822497

6.发布界面的搭建

6.1.1 发布的逻辑

  publishComment(content:string){
    this.commentList.unshift(new ReplyItemModel({
      // id: Math.random()的作用是生成一个基于随机数的临时唯一标识,但需注意:
      // 数值范围: 0 ≤ N < 1 (浮点数)
      // 格式示例: 0.1234567890123456
      // 非整型: 生成16位小数的浮点数
      //id不能重复
      id: Math.random(),
      avatar: 'https://picx.zhimg.com/027729d02bdf060e24973c3726fea9da_l.jpg?source=06d4cd63',
      author: '遇到困难睡大觉',
      content: '山外青山楼外楼,不回消息我记仇',
      time: '11-30',
      area: '安徽',
      likeNum: 0,
      likeFlag: false
    }))
  }

6.1.2 发布界面

@Preview
@Component
struct replay {
  content: string = ''
  @Link
  conmentsnum: number
  publish: (content: string) => void = () => {

  }

  build() {
    Row() {
      TextInput({ placeholder: '请留下你的评论~', text: $$this.content })
        .layoutWeight(1)
        .onSubmit(() => {
          this.publish(this.content)
          this.content = ''
        })
      Button('发布')
        .onClick(() => {

          this.publish(this.content)
          this.content = ''
          this.conmentsnum++

        })
    }
    .width('100%')
    .padding(12)
  }
}

export { replay }

http://www.kler.cn/a/576356.html

相关文章:

  • 考研题库与考研真题分别应该如何使用?
  • 搭建一套东郊到家上门按摩app需要多少钱?
  • 恶劣天候三维目标检测论文列表整理
  • eclipse查看源码
  • 自学Java-JavaSE基础加强(Java网络编程)
  • 大白话CSS 中的box-sizing属性,它有哪些值以及各自的作用
  • 【笔记】记一次easyExcel中注解ExcelProperty映射字段赋值无效问题
  • G1,最大的特点是什么,标记位图,卡表卡页,SATB又分别是什么?
  • 统一数据返回格式
  • 【NetTopologySuite类库】geojson和shp互转,和自定义对象互转
  • Kotlin字符串操作在Android开发中的应用示例
  • Java网络爬虫工程
  • 深度学习(斋藤)学习笔记(五)-反向传播2
  • 【卫星语音通信】神经网络语音编解码算法:AudioDec
  • 常见Web应用源码泄露问题
  • 揭开Android View的神秘面纱:深入探索工作原理
  • Go语言集成DeepSeek API和GoFly框架文本编辑器实现流式输出和对话(GoFly快速开发框架)
  • vue的el-form-item循环检验rules
  • AWS DynamoDB深度解析:高并发场景下的NoSQL数据库设计与优化实践
  • 重学 Android 自定义 View 系列(十一):文字跑马灯剖析