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

 

目录

 前言

功能展示

整体页面布局

最新和最热 

写评论 

点赞功能 

界面构建

 初始数据的准备

 列表项部分的渲染

底部区域 

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部分

@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

InfoCom部分

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=trueonSort=(type:number)=>{}build() {Row(){Text('全部评论').fontSize(20).fontWeight(FontWeight.Bold)Row(){Button('最新').ButStyle(!this.click).onClick(()=>{this.click=truethis.onSort(0)})Button('最热').ButStyle(this.click).onClick(()=>{this.click=falsethis.onSort(1)})}}.justifyContent(FlexAlign.SpaceBetween).padding({left:20,right:20}).width('100%').height(60)}
}
export default InfoCom

InfoItem部分

import { CommentDate } from '../model/CommentDate'@Component
struct InfoItem {@Prop itemObj:CommentDate@Prop index:numberonLikeClick=(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

CommentDate部分

// 准备评论数据类
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=avatarthis.name=namethis.level=levelthis.likenum=likenumthis.commentext=commentextthis.islike=islikethis.time=timethis.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
}

Index部分

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%')}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/407260.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

“游戏开发效率革命:AI绘画案例分享,大专生如何实现工作效率十倍提升与副业拓展“

一、游戏开发者的日常 我叫李明&#xff0c;是一名计算机专业的大专生。自从毕业以来&#xff0c;我就一直在一家游戏开发公司工作&#xff0c;转眼间&#xff0c;已经五年了。五年的时光&#xff0c;我从一个职场小白成长为了一名熟练的游戏开发者。但随之而来的&#xff0c;是…

GROUP_CONCAT 用法详解(Mysql)

GROUP_CONCAT GROUP_CONCAT 是 MySQL 中的一个聚合函数&#xff0c;用于将分组后的多行数据连接成一个单一的字符串。 通常用于将某个列的多个值合并到一个字符串中&#xff0c;以便更方便地显示或处理数据。 GROUP_CONCAT([DISTINCT] column_name[ORDER BY column_name [ASC…

Android SDK 遇到的坑之 AIUI(星火大模型)

目录 一、AIUI 二、常见错误 2.1 唤醒无效 2.2 错误码:600103 1、存放唤醒词等资源的路径 2、aiui_phone.cfg 文件配置 3、vtn.ini 文件配置 2.3 错误码:600022 相关推荐 一、AIUI 需要给桌面机器人(医康养)应用做语音指引/控制/健康咨询等功能&#xff0c;根据调研选择A…

书生大模型实战营第三期基础岛第二课——8G 显存玩转书生大模型 Demo

8G 显存玩转书生大模型 Demo 基础任务进阶作业一&#xff1a;进阶作业二&#xff1a; 基础任务 使用 Cli Demo 完成 InternLM2-Chat-1.8B 模型的部署&#xff0c;并生成 300 字小故事&#xff0c;记录复现过程并截图。 创建conda环境 # 创建环境 conda create -n demo pytho…

golang实现一个简单的rpc框架

前言 RPC在分布式系统中经常使用&#xff0c;这里写一个简单的demo实践一下。 code 先生成 go.mod 文件 go mod init rpc-try01定义方法 package model// Args 是 RPC 方法的参数结构体 type Args struct {A, B int }// Arith 定义了一个简单的算术服务 type Arith struct{…

工业4G路由器

设备概述 路由器是基于4G 技术研发的无线路由网关设备&#xff0c;除了具备传统路由器 的 VPN 、防火墙、 NAT 、 PPPoE 、 DHCP 等功能之外&#xff0c;还能支持 4G 无线拨号&#xff0c;提供最高可达 150Mbps 的无线高速带宽。路由器支持四个以太网接口&#xff0c;可更好…

产品需求文档

一、产品需求文档常用形式 RP&#xff1a;主要借助原型绘制工具绘制原型 包括产品简介&#xff1a;版本说明、交互自查表 产品概览&#xff1a;功能清单、项目排期 产品结构&#xff1a;结构图、流程图 产品原型&#xff1a;全局说明、具体原型、功能说明 非功能需求&…

揭秘!挑选随身WiFi的终极攻略:一篇文章教会你怎么挑选随身WiFi,学会对比各项参数,随身WiFi哪个好?

对于不方便拉宽带的大流量使用者&#xff0c;随身WiFi尤为重要。面对市场上琳琅满目的随身WiFi品牌和型号&#xff0c;许多用户感到无从下手。不同随身WiFi在性能、价格、续航等方面各有优势&#xff0c;如何挑选一款适合自己的随身WiFi成为了一大难题。本文将为您详细解析随身…

循环神经网络RNN时间序列预测与MLP比较

1 序列数据 利用CNN构建图像识别模型&#xff0c;对每个样本的假设是独立同分布的&#xff0c;然而,大多数的数据并非如此。例如,文章中的单词是按顺序写的,如果顺序被随机地重排,就很难理解文章原始的意思。同样,视频中的图像帧、对话中的音频信号以及网站上的浏览行为都是有…

VMware Workstation Pro 下载

文章目录 VMware Workstation ProVMware下载与安装 VMware Workstation Pro VMware Workstation Pro 对个人用户已经完全免费&#xff01; VMware下载与安装 第一步&#xff1a;进入vmware的官网 VMWare已被收购&#xff0c;因此它会跳到&#xff0c; Broadcom 注册页面&…

命令模式:如何利用命令模式实现手游后端架构?

成长路上不孤单&#x1f60a;【14后boy&#xff0c;C爱好者&#xff0c;持续分享所学&#xff0c;如有需要欢迎收藏转发&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#xff01;&#xff01;&#xff01;接上篇博文&#xf…

【React原理 - 任务调度和时间分片详解】

概述 在React15的时候&#xff0c;React使用的是从根节点往下递归的方式同步创建虚拟Dom&#xff0c;由于递归具有同步不可中断的特性&#xff0c;所以当执行长任务时(通常以60帧为标准&#xff0c;即16.6ms)就会长时间占用主线程长时间无响应&#xff0c;导致页面卡顿&#x…

通过C# 读取PDF页面大小、方向、旋转角度

在处理PDF文件时&#xff0c;了解页面的大小、方向和旋转角度等信息对于PDF的显示、打印和布局设计至关重要。本文将介绍如何使用免费.NET 库通过C#来读取PDF页面的这些属性。 文章目录 C# 读取PDF页面大小&#xff08;宽度、高度&#xff09;C# 判断PDF页面方向C# 检测PDF页面…

批发部小程序怎么制作 批发配送系统开发方法

很多领导想要做一个自己公司的批发部小程序系统&#xff0c;但是不知道该怎么做&#xff0c;本次瀚林就为大家详细介绍一下各种批发部小程序系统的开发制作方法为大家做参考。 目前市面上的批发部有很多类型例如常见的&#xff1a;食品、鲜花、零售批发商、冻品、百货、批发城、…

实现BeanPostProcessor

文章目录 1.实现初始化方法1.目录2.InitializingBean.java3.MonsterService.java 实现初始化接口4.SunSpringApplicationContext.java 调用初始化方法5.测试 2.实现后置处理器1.目录2.BeanPostProcessor.java 后置处理器接口3.SunBeanProcessor.java 自定义后置处理器4.SunSpri…

【Python】函数的定义和调用、形参和实参、函数的返回值、多元赋值、全局和局部变量

文章目录 函数的定义函数的调用形参和实参函数的返回值一个 return多个 return多元赋值 变量作用域函数内的变量全局变量和局部变量修改全局变量 函数的定义 函数的定义&#xff1a;分配任务 def 函数名(形参列表):函数体return 返回值def&#xff1a;define&#xff0c;定义…

AI革新下的社交媒体:揭秘Facebook如何利用智能算法

在社交媒体领域&#xff0c;Facebook一直走在技术创新的前沿。随着人工智能&#xff08;AI&#xff09;的飞速发展&#xff0c;Facebook通过智能算法不断革新用户体验、提升平台效率&#xff0c;并推动社交互动的新形式。本文将详细探讨Facebook如何利用AI技术&#xff0c;从个…

ElasticSearch IK分词器的MySQL热部署字典(Docker)

1.下载插件源码 找到自己对应ES版本的下载 Releases infinilabs/analysis-ik GitHub 2.添加mysql驱动依赖 <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version><…

C++模拟实现priority_queue(优先级队列)

一、priority_queue的函数接口 从上图我们可以看出&#xff0c; priority_queue也是一个容器适配器&#xff0c;我们使用vector容器来模拟实现priority_queue。 namespace bit{#include<vector>#include<functional>template <class T, class Container vector…

【数据结构】动态顺序表的实现

1.什么是数据结构 数据结构就是把数据元素按照一定的关系组织起来的集合&#xff0c;用来组织和存储数据。通过数据结构&#xff0c;能够有效的将数据组织和管理在一起&#xff0c;按照我们的方式任意对数据进行增删查改等操作。 2.数据结构的分类 数据结构大概可分为逻辑结构…