赞
踩
目录
个人主页→VON
收录专栏→鸿蒙开发小型案例总结
基础语法部分会发布于github 和 gitee上面(暂未发布)
由于一些个人的特殊原因,基础部分的代码迟迟未进行上传,我会尽快进行整理发布后会第一时间进行通知,希望大家多多谅解
鸿蒙基础部分到这里也要和大家说再见了,此案例所用到的知识点众多构建过程较为复杂。希望读者们能够认真观看。我也会尽力帮助大家梳理代码以及各各部分的逻辑及其思路。
此案例可以应用于多个地方,比如博客,短视频app等都可以进行应用
整体分为三大部分,分别为头部、中间、底部。认真观察不难发现头部区域采用了Row,中间区域采用了List,底部区域采用了两个Row。整体布局为层叠布局。
最新和最热点击时显示的效果不同,并且列表所展示的也不同。点击最新时评论的内容会根据时间进行排序,最热时会根据点赞数进行排序。
自己可以在写评论处发布评论,列表会根据评论进行渲染。
由于代码的长度限制,过于基础的部分不在进行逐一讲解,希望大家谅解
最新和最热是两个按钮组件,Extend装饰器进行修改,当未被选中时是一种状态,被选中时是另外一种状态。这两种状态的样式我是根据最左侧的颜色来进行适当调整的,大家也可以效仿。
初始数据是自己进行构建的一些数据,这些数据被打包在CommentDate中,其中点赞数和等级是随机的,其他部分都是自定义的。因为这是一个离线的静态页面,并没有实现交互功能所以目前只能这样来代替。
渲染部分用到了CommentDate中的数据来进行逐一渲染的,因为实现交互的是子组件,但是要修改的部分是父组件的一些内容,所以对于可变的数据用到了Prop装饰器进行的装饰。
底部区域实现了双向绑定,当输入评论并且单击回车键后数据会进行增加。并且会排在首位,也就是下标为0的位置增添了一个全新的数据。
一些函数的定义及其功能的实现全都在index页面来进行实现的,所以这一界面要尽量保持简介,每一部分都可以进行抽取单独进行ui界面的构建,通过import来进行导入即可。
鸿蒙开发中的List组件是一个功能强大且常用的UI组件,用于呈现连续的数据列表。
@Prop是一个方便的注解,用于在鸿蒙应用开发中实现组件之间的数据传递。
在现代软件开发中,组件化和数据传递是提高开发效率和代码可维护性的关键环节。特别是在鸿蒙这类分布式操作系统中,对组件间数据传递机制的优化尤为重要。下面将详细探讨@Prop注解的作用、限制条件、使用规则以及具体的使用场景。
@Component struct BottomCom { @State txt:string='' onSubmitComment=(content:string)=>{} build() { Row(){ Row(){ Image($r('app.media.edit')) .width(20) .margin({left:10}) TextInput({ placeholder:'写评论...', // 双向绑定 text:$$this.txt }) .backgroundColor(Color.Transparent) .fontSize(18) // 回车 .onSubmit(()=>{ this.onSubmitComment(this.txt) }) } .height(40) .backgroundColor('#f5f6f5') .borderRadius(20) .margin({left:15,right:20,top:10,bottom:10}) .layoutWeight(1) Image($r('app.media.love_stare')) .width(25) Image($r("app.media.like_stare")) .width(25) .margin({left:15,right:10}) } .width('100%') .height(60) } } export default BottomCom
import BottomCom from './BottomCom' @Extend(Button) function ButStyle(click:boolean){ .fontSize(12) .border({width:1,color:click?'#fff':'#ffbeb7b7'}) .width(46) .height(32) .padding({left:5,right:5}) .fontColor(click ? '#80555858' :'#ff1f1e1e') .backgroundColor(click ? '#fff' : '#1ae0e0e0') } @Component struct InfoCom { @State click:boolean=true onSort=(type:number)=>{ } build() { Row(){ Text('全部评论') .fontSize(20) .fontWeight(FontWeight.Bold) Row(){ Button('最新') .ButStyle(!this.click) .onClick(()=>{ this.click=true this.onSort(0) }) Button('最热') .ButStyle(this.click) .onClick(()=>{ this.click=false this.onSort(1) }) } } .justifyContent(FlexAlign.SpaceBetween) .padding({left:20,right:20}) .width('100%') .height(60) } } export default InfoCom
import { CommentDate } from '../model/CommentDate' @Component struct InfoItem { @Prop itemObj:CommentDate @Prop index:number onLikeClick=(index:number)=>{ } build() { // 列表项组件 Column(){ Row(){ // 头像 Image(this.itemObj.avatar) .width(30) .borderRadius(15) .margin({top:10,right:5}) // 昵称 Text(this.itemObj.name) .fontColor('#808d8585') .fontSize(14) .margin({top:10,left:5}) // 等级 Image(this.itemObj.levelIcon) .width(20) .margin({left:10,top:10}) } // 评论内容 Text(this.itemObj.commentext) .fontSize(13) .fontWeight(700) .margin({top:10,left:40}) Row(){ // 时间 Text(this.itemObj.timeString) .fontSize(10) .fontColor(Color.Gray) // 点赞 Row(){ Image(this.itemObj.islike ? $r('app.media.like_end') : $r('app.media.like_stare')) .width(12) Text(this.itemObj.likenum.toString()) .fontSize(10) .fontColor(this.itemObj.islike ? Color.Red : Color.Gray) } .onClick(()=>{ this.onLikeClick(this.index) }) } .width('100%') .padding({left:40,right:20,top:15}) .justifyContent(FlexAlign.SpaceBetween) } .alignItems(HorizontalAlign.Start) .padding({left:15,top:10}) } } export default InfoItem
// 准备评论数据类 export class CommentDate{ avatar:ResourceStr;// 头像 name:string;// 昵称 level:number;// 用户等级 likenum:number;// 点赞数量 commentext:string;// 评论内容 islike:boolean;// 是否喜欢 levelIcon:Resource;// level等级 timeString:string;// 发布时间 time:number // 时间戳 constructor(avatar: ResourceStr, name: string, level: number, likenum: number, commentext: string, islike: boolean,time:number) { this.avatar=avatar this.name=name this.level=level this.likenum=likenum this.commentext=commentext this.islike=islike this.time=time this.levelIcon=this.convertLevel(this.level) this.timeString=this.convertTime(time) } //时间转换函数 convertTime(time:number){ const currentTimestamp = new Date().getTime(); // 转换为秒 const timeDifference = (currentTimestamp-time)/1000; console.log(timeDifference.toString()) if(timeDifference<0 || timeDifference==0){ return '刚刚'; }else if(timeDifference<60){ return `${Math.floor(timeDifference)}秒前`; }else if(timeDifference<3600){ return `${Math.floor(timeDifference/60)}分钟前`; }else if(timeDifference<86400){ return `${Math.floor(timeDifference/3600)}小时前`; }else if(timeDifference<604800){ return `${Math.floor(timeDifference/86400)}天前`; }else if(timeDifference<2592000){ return `${Math.floor(timeDifference/604800)}周前`; }else if(timeDifference<31536000){ return `${Math.floor(timeDifference/2592000)}个月前`; }else{ return `${Math.floor(timeDifference/31536000)}年前`; } } // 等级图片获取 convertLevel(Level:number){ const iconList=[ $r('app.media.lv1'), $r('app.media.lv2'), $r('app.media.lv3'), $r('app.media.lv4'), $r('app.media.lv5'), $r('app.media.lv6') ] return iconList[Level] } } // 封装一个方法,创建假数据 export const createListRange=():CommentDate[]=>{ let result:CommentDate[]=new Array() result=[ new CommentDate($r('app.media.tx_01'),'JohnYan',Math.floor(Math.random()*6),Math.floor(Math.random()*100),'要是那天,我抓住你就好了',false,1705850201128), new CommentDate($r('app.media.tx_03'),'cv工程师',Math.floor(Math.random()*6),Math.floor(Math.random()*100),'故事不长,也不难讲,相识一场,爱而不得',false,1643800201128), new CommentDate($r('app.media.tx_04'),'风行水上',Math.floor(Math.random()*6),Math.floor(Math.random()*100),'后来啊,书没有读好,喜欢的人也没有在一起',false,1715850201128), new CommentDate($r('app.media.tx_05'),'枫以',Math.floor(Math.random()*6),Math.floor(Math.random()*100),'你根本忘不了一个认认真真爱过的人,你以为错过的是一个人,其实你错过的是一整个人生',false,1680850201128), new CommentDate($r('app.media.tx_06'),'幼稚园里的幼稚鬼',Math.floor(Math.random()*6),Math.floor(Math.random()*100),'有些伤痛即使已经痊愈,也会留下难以愈合的伤疤',false,1705850201128), new CommentDate($r('app.media.tx_07'),'浮临子',Math.floor(Math.random()*6),Math.floor(Math.random()*100),'不是所有的梦想都会成真,不是所有的伤痛都能愈合,但我们要有勇气继续前行',false,1625050201128), new CommentDate($r('app.media.tx_08'),'╭⌒浅浅笑',Math.floor(Math.random()*6),Math.floor(Math.random()*100),'孤独并不可怕,可怕的是渴望有人陪伴而得不到',false,1720850201128), new CommentDate($r('app.media.tx_09'),'枕头说它不想醒',Math.floor(Math.random()*6),Math.floor(Math.random()*100),'可惜爱不是写诗 我只能欲言又止',false,1745050201128) ] return result }
import InfoCom from '../components/InfoCom' import BottomCom from '../components/BottomCom' import InfoItem from '../components/InfoItem' import {CommentDate,createListRange} from '../model/CommentDate' @Entry @Component struct Index { // 处理点赞时的方法 handlelike(index:number){ // 要有唯一标识 // AlertDialog.show({ // message:index.toString() // }) // 父组件的方法,如果抽取出来,如果直接传递给子组件会有this指向问题,this通常直接指向调用者 // 需要用箭头函数包一层,保证this还是指向父组件 // 根据index进行判断 let itemData=this.commentList[index] if(itemData.islike){ itemData.likenum-=1 }else{ itemData.likenum+=1 } itemData.islike= !itemData.islike // 对于复杂类型:状态对象,状态数组,只会对第一层数据进行监视变化 this.commentList.splice(index,1,itemData) } // 处理提交 handleSubmit(content:string){ // 将数据添加到数组最前面 const newItem:CommentDate=new CommentDate( $r('app.media.tx_01'),'我',2,0,content,false,new Date().getTime() ) this.commentList=[newItem,...this.commentList] } // 处理排序 handleSort(type:number){ if(type==0){ this.commentList.sort((a,b)=>{ return b.time-a.time }) }else if(type==1){ this.commentList.sort((a,b)=>{ return b.likenum-a.likenum }) } } // 初始化数据 @State commentList:CommentDate[]=createListRange() // 生命周期函数,会自动执行 aboutToAppear(): void { this.handleSort(0) } build() { Column(){ //头部 InfoCom({ onSort:(type:number)=>{ this.handleSort(type) } }) //中间 List(){ ForEach(this.commentList,(item:CommentDate,index:number)=>{ ListItem(){ // 列表项组件 InfoItem({ index:index, itemObj:item, onLikeClick:(index:number)=>{ // 此处的this就是父组件 this.handlelike(index) } }) } }) } .width('100%') .layoutWeight(1) //底部 BottomCom({ onSubmitComment:(content:string)=>{ this.handleSubmit(content) } }) } .width('100%') .height('100%') } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。