評論頁面小demo
效果展示
1.拆解組件,分層搭建
我們將整個評論頁面拆解為三個組件,分別是頭部導航,評論項,回復三個部分,然后統一在index界面導入
2.頭部導航界面搭建
@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.評論項搭建
@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 // 評論的idcontent: string // 評論內容time: string // 發表時間area: string // 地區likeNum: number // 點贊數量likeFlag: boolean | null // 當前用戶是否點過贊
}export class ReplyItemModel implements ReplyItem {avatar: ResourceStr = ''author: string = ''id: number = 0content: string = ''time: string = ''area: string = ''likeNum: number = 0likeFlag: boolean | null = nullconstructor(model: ReplyItem) {this.avatar = model.avatarthis.author = model.authorthis.id = model.idthis.content = model.contentthis.time = model.timethis.area = model.areathis.likeNum = model.likeNumthis.likeFlag = model.likeFlag}
}
4.搭建評論列表界面
List() {ForEach(this.commentList, (item: ReplyItemModel) => {ListItem() {HmCommentItem({commentInfo: item,//但凡傳函數吧必須用箭頭函數包裹!changeLike:(id:number)=>{this.changeLike(id)}})}})}.layoutWeight(1)
- 這里需要注意幾點
- List里面必須放置
ListItem()
- 評論列表的高度可以給一個自適應,這樣可以讓列列表超出屏幕的高度時實現自適應
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父界面進行傳值
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 = ''@Linkconmentsnum: numberpublish: (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 }