目录
前言
功能展示
整体页面布局
最新和最热
写批评
点赞功能
界面构建
初始数据的预备
列表项部分的渲染
底部区域
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=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
复制代码 InfoItem部分
- 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
复制代码 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=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
- }
复制代码 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%')
- }
- }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |