【HarmonyOS NEXT星河版开发学习】综合测试案例-各平台批评部分 ...

打印 上一主题 下一主题

主题 648|帖子 648|积分 1944

 
目录
 前言
功能展示
整体页面布局
最新和最热 
写批评 
点赞功能 
界面构建
 初始数据的预备
 列表项部分的渲染
底部区域 
index部分 
 知识点概述
List组件
List组件简介
ListItem组件详解
ListItemGroup组件先容
ForEach循环渲染
列表分割线设置
列表分列方向设置
索引值计算规则
@Prop装饰器 
@Prop注解的基本作用
@Prop注解的限制条件
@Prop注解的使用规则
@Prop注解的具体使用场景
全套代码
BottomCom部分
InfoCom部分
InfoItem部分
CommentDate部分
Index部分


   
个人主页→VON
  
  
收录专栏→鸿蒙开发小型案例总结​​​​​

  
  
基础语法部分会发布于github 和 gitee上面(暂未发布)

  
  由于一些个人的特殊原因,基础部分的代码迟迟未举行上传,我会尽快举行整理发布后会第一时间举行关照,希望大家多多谅解
  

 前言

   鸿蒙基础部分到这里也要和大家说再见了,此案例所用到的知识点众多构建过程较为复杂。希望读者们能够认真观看。我也会努力帮助大家梳理代码以及各各部分的逻辑及其思绪。
  
此案例可以应用于多个地方,比如博客,短视频app等都可以举行应用

功能展示

整体页面布局


   整体分为三大部分,分别为头部、中间、底部。认真观察不难发现头部区域采用了Row,中间区域采用了List,底部区域采用了两个Row。整体布局为层叠布局。 
  最新和最热 

 

   最新和最热门击时体现的结果不同,并且列表所展示的也不同。点击最新时批评的内容会根据时间举行排序,最热时会根据点赞数举行排序。
  写批评 



    自己可以在写批评处发布批评,列表会根据批评举行渲染。
  点赞功能 

 

界面构建

由于代码的长度限制,过于基础的部分不在举行逐一解说,希望大家谅解


    最新和最热是两个按钮组件,Extend装饰器举行修改,当未被选中时是一种状态,被选中时是别的一种状态。这两种状态的样式我是根据最左侧的颜色来举行适当调解的,大家也可以效仿。
   初始数据的预备


    初始数据是自己举行构建的一些数据,这些数据被打包在CommentDate中,此中点赞数和品级是随机的,其他部分都是自定义的。由于这是一个离线的静态页面,并没有实现交互功能所以现在只能如许来取代。
   列表项部分的渲染


   渲染部分用到了CommentDate中的数据来举行逐一渲染的,由于实现交互的是子组件,但是要修改的部分是父组件的一些内容,所以对于可变的数据用到了Prop装饰器举行的装饰。 
  底部区域 


   底部区域实现了双向绑定,当输入批评并且单击回车键后数据会举行增加。并且会排在首位,也就是下标为0的位置增添了一个全新的数据。 
  index部分 

 

   一些函数的定义及其功能的实现全都在index页面来举行实现的,所以这一界面要尽量保持简介,每一部分都可以举行抽取单独举行ui界面的构建,通过import来举行导入即可。 
   知识点概述

List组件

鸿蒙开发中的List组件是一个功能强盛且常用的UI组件,用于呈现一连的数据列表。
List组件简介



  • 基础定义:List组件是一种容器组件,用于展示一系列相同宽度的列表项,适合一连、多行呈现同类数据,例如图片和文本。
  • 参数配置:List组件继承三个主要参数:space(子组件主轴方向的间隔)、initialIndex(初次加载时视口起始位置体现的item索引)、scroller(可滚动组件的控制器)。
ListItem组件详解



  • 基本概念:ListItem是具体的列表项组件,必须配合List使用,用于展示每个具体的数据项。
  • 参数设置:主要参数包括selectable(是否可被鼠标框选)和swipeAction(设置划出组件的属性)。
ListItemGroup组件先容



  • 功能描述:用于展示列表项分组,宽度默认布满List组件,也必须配合List使用。
  • 主要参数:header(头部组件)、footer(尾部组件)和space(列表项间距)。
ForEach循环渲染



  • 应用场景:当列表由多个相似或重复的列表项组成时,为淘汰代码冗余,可以使用ForEach举行循环渲染。
  • 工作原理:ForEach接口基于数组范例数据举行循环渲染,需与容器组件配合使用,如List。
列表分割线设置



  • 功能解释:通过divider属性设置列表项之间的分割线样式,提升视觉上的区分度和美观性。
  • 参数说明:主要参数包括strokeWidth(分割线的线宽)、color(分割线的颜色)、startMargin和endMargin(分割线间隔列表侧边起始端和结束端的间隔)。
列表分列方向设置



  • 垂直分列:List默认采用垂直分列方式,即列表项按垂直方向线性分列。
  • 程度分列:通过设置listDirection属性为Axis.Horizontal,可以实现列表项的程度分列。
索引值计算规则



  • 规则概述:索引值用来确定列表项在列表中的具体位置,初次加载时默认从0开始。
  • 细节掌握:初始索引可以通过initialIndex参数手动设置,但需确保索引值不凌驾列表项总数。
@Prop装饰器 

@Prop是一个方便的注解,用于在鸿蒙应用开发中实现组件之间的数据转达
在现代软件开发中,组件化和数据转达是提高开发效率和代码可维护性的关键环节。特别是在鸿蒙这类分布式利用系统中,对组件间数据转达机制的优化尤为紧张。下面将具体探讨@Prop注解的作用、限制条件、使用规则以及具体的使用场景。
@Prop注解的基本作用



  • 单向数据同步:@Prop注解主要用于实现组件间的单向数据同步。这意味着,当父组件的状态发生改变时,这些改变会通过@Prop注解转达给子组件,但子组件对这些属性的修改不会影响到父组件。
  • 支持的数据范例:@Prop能够处理各种基本数据范例,包括字符串、数字、布尔值和罗列范例。这保证了其在不同场景下的机动性和实用性。
@Prop注解的限制条件



  • 复杂范例的深拷贝:当@Prop涉及到复杂数据范例时(如对象或数组),会举行深拷贝利用。这一过程中,除了基本范例(如字符串、数字)、Map、Set、Date和Array外,其他范例大概会丢失。
  • 使用场景限制:@Prop不能在@Entry装饰的自定义组件中使用。这限定了@Prop的使用范围,通常仅实用于页面级组件。
@Prop注解的使用规则



  • 参数配置:@Prop不必要特定参数,其同步范例为单向同步。
  • 范例要求严格:使用@Prop时必须明确指定被装饰变量的具体范例,不允许使用any范例,也不允许使用undefined和null作为默认值。
@Prop注解的具体使用场景



  • 简单数据范例同步:例如,父组件中的@State状态可以通过@Prop注解转达给子组件。如果父组件的状态发生更新,子组件的@Prop也会相应更新。但如果子组件实验修改这些属性,更改不会反映到父组件中。
  • 数组项同步:当父组件中的@State数组项更新时,子组件中对应的@Prop也会同步更新。例如,父组件可以包罗一个数字数组,每个元素用来初始化子组件中的一个@Prop。同样,子组件对@Prop的修改不会反映到父组件中。
  • 类对象属性同步:父组件中的@State类对象可以用来初始化子组件的@Prop。任何父组件中对象属性的更新都会同步到子组件,但子组件对@Prop的修改仍旧不会反向同步到父组件。
全套代码


BottomCom部分

  1. @Component
  2. struct BottomCom {
  3.   @State txt:string=''
  4.   onSubmitComment=(content:string)=>{}
  5.   build() {
  6.     Row(){
  7.       Row(){
  8.         Image($r('app.media.edit'))
  9.           .width(20)
  10.           .margin({left:10})
  11.         TextInput({
  12.           placeholder:'写评论...',
  13.           // 双向绑定
  14.           text:$$this.txt
  15.         })
  16.           .backgroundColor(Color.Transparent)
  17.           .fontSize(18)
  18.           // 回车
  19.           .onSubmit(()=>{
  20.             this.onSubmitComment(this.txt)
  21.           })
  22.       }
  23.       .height(40)
  24.       .backgroundColor('#f5f6f5')
  25.       .borderRadius(20)
  26.       .margin({left:15,right:20,top:10,bottom:10})
  27.       .layoutWeight(1)
  28.       Image($r('app.media.love_stare'))
  29.         .width(25)
  30.       Image($r("app.media.like_stare"))
  31.         .width(25)
  32.         .margin({left:15,right:10})
  33.     }
  34.     .width('100%')
  35.     .height(60)
  36.   }
  37. }
  38. export default BottomCom
复制代码
InfoCom部分

  1. import BottomCom from './BottomCom'
  2. @Extend(Button)
  3. function ButStyle(click:boolean){
  4.   .fontSize(12)
  5.   .border({width:1,color:click?'#fff':'#ffbeb7b7'})
  6.   .width(46)
  7.   .height(32)
  8.   .padding({left:5,right:5})
  9.   .fontColor(click ? '#80555858' :'#ff1f1e1e')
  10.   .backgroundColor(click ? '#fff' : '#1ae0e0e0')
  11. }
  12. @Component
  13. struct InfoCom {
  14.   @State click:boolean=true
  15.   onSort=(type:number)=>{
  16.   }
  17.   build() {
  18.     Row(){
  19.       Text('全部评论')
  20.         .fontSize(20)
  21.         .fontWeight(FontWeight.Bold)
  22.       Row(){
  23.         Button('最新')
  24.           .ButStyle(!this.click)
  25.           .onClick(()=>{
  26.             this.click=true
  27.             this.onSort(0)
  28.           })
  29.         Button('最热')
  30.           .ButStyle(this.click)
  31.           .onClick(()=>{
  32.             this.click=false
  33.             this.onSort(1)
  34.           })
  35.       }
  36.     }
  37.     .justifyContent(FlexAlign.SpaceBetween)
  38.     .padding({left:20,right:20})
  39.     .width('100%')
  40.     .height(60)
  41.   }
  42. }
  43. export default InfoCom
复制代码
InfoItem部分

  1. import { CommentDate } from '../model/CommentDate'
  2. @Component
  3. struct InfoItem {
  4.   @Prop itemObj:CommentDate
  5.   @Prop index:number
  6.   onLikeClick=(index:number)=>{
  7.   }
  8.   build() {
  9.     // 列表项组件
  10.     Column(){
  11.       Row(){
  12.         // 头像
  13.         Image(this.itemObj.avatar)
  14.           .width(30)
  15.           .borderRadius(15)
  16.           .margin({top:10,right:5})
  17.         // 昵称
  18.         Text(this.itemObj.name)
  19.           .fontColor('#808d8585')
  20.           .fontSize(14)
  21.           .margin({top:10,left:5})
  22.         // 等级
  23.         Image(this.itemObj.levelIcon)
  24.           .width(20)
  25.           .margin({left:10,top:10})
  26.       }
  27.       // 评论内容
  28.       Text(this.itemObj.commentext)
  29.         .fontSize(13)
  30.         .fontWeight(700)
  31.         .margin({top:10,left:40})
  32.       Row(){
  33.         // 时间
  34.         Text(this.itemObj.timeString)
  35.           .fontSize(10)
  36.           .fontColor(Color.Gray)
  37.         // 点赞
  38.         Row(){
  39.           Image(this.itemObj.islike ? $r('app.media.like_end') : $r('app.media.like_stare'))
  40.             .width(12)
  41.           Text(this.itemObj.likenum.toString())
  42.             .fontSize(10)
  43.             .fontColor(this.itemObj.islike ? Color.Red : Color.Gray)
  44.         }
  45.         .onClick(()=>{
  46.           this.onLikeClick(this.index)
  47.         })
  48.       }
  49.       .width('100%')
  50.       .padding({left:40,right:20,top:15})
  51.       .justifyContent(FlexAlign.SpaceBetween)
  52.     }
  53.     .alignItems(HorizontalAlign.Start)
  54.     .padding({left:15,top:10})
  55.   }
  56. }
  57. export default InfoItem
复制代码
CommentDate部分

  1. // 准备评论数据类
  2. export class CommentDate{
  3.   avatar:ResourceStr;// 头像
  4.   name:string;// 昵称
  5.   level:number;// 用户等级
  6.   likenum:number;// 点赞数量
  7.   commentext:string;// 评论内容
  8.   islike:boolean;// 是否喜欢
  9.   levelIcon:Resource;// level等级
  10.   timeString:string;// 发布时间
  11.   time:number // 时间戳
  12.   constructor(avatar: ResourceStr, name: string, level: number, likenum: number, commentext: string,
  13.               islike: boolean,time:number) {
  14.     this.avatar=avatar
  15.     this.name=name
  16.     this.level=level
  17.     this.likenum=likenum
  18.     this.commentext=commentext
  19.     this.islike=islike
  20.     this.time=time
  21.     this.levelIcon=this.convertLevel(this.level)
  22.     this.timeString=this.convertTime(time)
  23.   }
  24.   //时间转换函数
  25.   convertTime(time:number){
  26.     const currentTimestamp = new Date().getTime();
  27.     // 转换为秒
  28.     const timeDifference = (currentTimestamp-time)/1000;
  29.     console.log(timeDifference.toString())
  30.     if(timeDifference<0 || timeDifference==0){
  31.       return '刚刚';
  32.     }else if(timeDifference<60){
  33.       return `${Math.floor(timeDifference)}秒前`;
  34.     }else if(timeDifference<3600){
  35.       return `${Math.floor(timeDifference/60)}分钟前`;
  36.     }else if(timeDifference<86400){
  37.       return `${Math.floor(timeDifference/3600)}小时前`;
  38.     }else if(timeDifference<604800){
  39.       return `${Math.floor(timeDifference/86400)}天前`;
  40.     }else if(timeDifference<2592000){
  41.       return `${Math.floor(timeDifference/604800)}周前`;
  42.     }else if(timeDifference<31536000){
  43.       return `${Math.floor(timeDifference/2592000)}个月前`;
  44.     }else{
  45.       return `${Math.floor(timeDifference/31536000)}年前`;
  46.     }
  47.   }
  48.   // 等级图片获取
  49.   convertLevel(Level:number){
  50.     const iconList=[
  51.       $r('app.media.lv1'),
  52.       $r('app.media.lv2'),
  53.       $r('app.media.lv3'),
  54.       $r('app.media.lv4'),
  55.       $r('app.media.lv5'),
  56.       $r('app.media.lv6')
  57.     ]
  58.     return iconList[Level]
  59.   }
  60. }
  61. // 封装一个方法,创建假数据
  62. export const createListRange=():CommentDate[]=>{
  63.   let result:CommentDate[]=new Array()
  64.   result=[
  65.     new CommentDate($r('app.media.tx_01'),'JohnYan',Math.floor(Math.random()*6),Math.floor(Math.random()*100),'要是那天,我抓住你就好了',false,1705850201128),
  66.     new CommentDate($r('app.media.tx_03'),'cv工程师',Math.floor(Math.random()*6),Math.floor(Math.random()*100),'故事不长,也不难讲,相识一场,爱而不得',false,1643800201128),
  67.     new CommentDate($r('app.media.tx_04'),'风行水上',Math.floor(Math.random()*6),Math.floor(Math.random()*100),'后来啊,书没有读好,喜欢的人也没有在一起',false,1715850201128),
  68.     new CommentDate($r('app.media.tx_05'),'枫以',Math.floor(Math.random()*6),Math.floor(Math.random()*100),'你根本忘不了一个认认真真爱过的人,你以为错过的是一个人,其实你错过的是一整个人生',false,1680850201128),
  69.     new CommentDate($r('app.media.tx_06'),'幼稚园里的幼稚鬼',Math.floor(Math.random()*6),Math.floor(Math.random()*100),'有些伤痛即使已经痊愈,也会留下难以愈合的伤疤',false,1705850201128),
  70.     new CommentDate($r('app.media.tx_07'),'浮临子',Math.floor(Math.random()*6),Math.floor(Math.random()*100),'不是所有的梦想都会成真,不是所有的伤痛都能愈合,但我们要有勇气继续前行',false,1625050201128),
  71.     new CommentDate($r('app.media.tx_08'),'╭⌒浅浅笑',Math.floor(Math.random()*6),Math.floor(Math.random()*100),'孤独并不可怕,可怕的是渴望有人陪伴而得不到',false,1720850201128),
  72.     new CommentDate($r('app.media.tx_09'),'枕头说它不想醒',Math.floor(Math.random()*6),Math.floor(Math.random()*100),'可惜爱不是写诗 我只能欲言又止',false,1745050201128)
  73.   ]
  74.   return result
  75. }
复制代码
Index部分

  1. import InfoCom from '../components/InfoCom'
  2. import BottomCom from '../components/BottomCom'
  3. import InfoItem from '../components/InfoItem'
  4. import {CommentDate,createListRange} from '../model/CommentDate'
  5. @Entry
  6. @Component
  7. struct Index {
  8.   // 处理点赞时的方法
  9.   handlelike(index:number){
  10.     // 要有唯一标识
  11.     // AlertDialog.show({
  12.     //   message:index.toString()
  13.     // })
  14.     // 父组件的方法,如果抽取出来,如果直接传递给子组件会有this指向问题,this通常直接指向调用者
  15.     // 需要用箭头函数包一层,保证this还是指向父组件
  16.     // 根据index进行判断
  17.     let itemData=this.commentList[index]
  18.     if(itemData.islike){
  19.       itemData.likenum-=1
  20.     }else{
  21.       itemData.likenum+=1
  22.     }
  23.     itemData.islike= !itemData.islike
  24.     // 对于复杂类型:状态对象,状态数组,只会对第一层数据进行监视变化
  25.     this.commentList.splice(index,1,itemData)
  26.   }
  27.   // 处理提交
  28.   handleSubmit(content:string){
  29.     // 将数据添加到数组最前面
  30.     const newItem:CommentDate=new CommentDate(
  31.       $r('app.media.tx_01'),'我',2,0,content,false,new Date().getTime()
  32.     )
  33.     this.commentList=[newItem,...this.commentList]
  34.   }
  35.   // 处理排序
  36.   handleSort(type:number){
  37.     if(type==0){
  38.       this.commentList.sort((a,b)=>{
  39.         return b.time-a.time
  40.       })
  41.     }else if(type==1){
  42.       this.commentList.sort((a,b)=>{
  43.         return b.likenum-a.likenum
  44.       })
  45.     }
  46.   }
  47.   // 初始化数据
  48.   @State commentList:CommentDate[]=createListRange()
  49.   // 生命周期函数,会自动执行
  50.   aboutToAppear(): void {
  51.     this.handleSort(0)
  52.   }
  53.   build() {
  54.     Column(){
  55.       //头部
  56.       InfoCom({
  57.         onSort:(type:number)=>{
  58.           this.handleSort(type)
  59.         }
  60.       })
  61.       //中间
  62.       List(){
  63.         ForEach(this.commentList,(item:CommentDate,index:number)=>{
  64.           ListItem(){
  65.             // 列表项组件
  66.             InfoItem({
  67.               index:index,
  68.               itemObj:item,
  69.               onLikeClick:(index:number)=>{
  70.                 // 此处的this就是父组件
  71.                 this.handlelike(index)
  72.               }
  73.             })
  74.           }
  75.         })
  76.       }
  77.       .width('100%')
  78.       .layoutWeight(1)
  79.       //底部
  80.       BottomCom({
  81.         onSubmitComment:(content:string)=>{
  82.           this.handleSubmit(content)
  83.         }
  84.       })
  85.     }
  86.     .width('100%')
  87.     .height('100%')
  88.   }
  89. }
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

钜形不锈钢水箱

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表