赞
踩
数据结构如下:评论列表中带有的每条评论嵌套回复列表
- // 评论字段
- export interface CommentInterface {
- id:number,//主键
- content:string,//评论内容
- parentId:number,//父节点id
- type:string,// 类型
- topId:number,//顶级节点id
- relationId:number,//影片id
- createTime:string,//创建时间
- updateTime:string,//更新时间
- replyCount:number,//回复数量
- userId:string,//用户id
- username:string,//用户名
- avater:string,//用户头像
- replyUserId:string,//被回复者id
- replyUserName:string,//被回复者名称
- showCommentCount:string,//显示的回复数量
- replyPageNum:number,// 回复数量
- replyList:Array<CommentInterface>// 回复列表
- }
后端接口返回格式如下:
- [
- {
- "id": 112,
- "content": "精彩",
- "parentId": null,
- "topId": null,
- "relationId": 72667,
- "type": "MOVIE",
- "createTime": "2024-05-25T07:17:28.000+0000",
- "updateTime": null,
- "replyCount": 1,
- "userId": "灯火阑珊",
- "username": "灯火阑珊2",
- "avater": "/static/user/avater/灯火阑珊.jpg",
- "replyUserId": null,
- "replyUserName": null,
- "replyList": [
- {
- "id": 148,
- "content": "666",
- "parentId": 112,
- "topId": 112,
- "relationId": 72667,
- "type": "MOVIE",
- "createTime": "2024-05-26T08:07:53.000+0000",
- "updateTime": null,
- "replyCount": 0,
- "userId": "初晓微芒",
- "username": "初晓微芒",
- "avater": "/static/user/avater/初晓微芒.jpg",
- "replyUserId": "灯火阑珊",
- "replyUserName": "灯火阑珊2",
- "replyList": null
- }
- ]
- }
- ]
展示效果如下
点击回复,向item.replyList中插入一条回复内容,视图不更新,但数据库已经插入成功
- // 发送评论
- insertCommentService(commentItem).then((res) => {
- if (this.firstComment) { // 二级评论,相当于回复,插入一条回复
- this.commentList[this.replyIndex].replyList.push(res.data);
- } else { // 一级评论
- this.commentList.push(res.data);
- }
- this.dialogController?.close();
- this.replyComment = this.firstComment = null;
- this.text = '';
- this.focusableInput = false;
- }).finally(() => {
- this.loading = false;
- });
数据库中显示插入数据成功了,但是视图没有更新
解决办法1(推荐第2种方法):
1、把原来的数组解构重新赋值,
2、往新定义的数组里面添加回复数据
3、重新赋值给原来的数据,即可实现视图更新,
原理:强制改变原数组的内存地址,让视图重新渲染
- // 发送评论
- insertCommentService(commentItem).then((res) => {
- // 必须重新解构,然后再赋值,否则添加回复不生效
- const commentList = [...this.commentList];
- if (this.firstComment) { // 二级评论,相当于回复
- commentList[this.replyIndex].replyList.push(res.data);
- } else { // 一级评论
- commentList.push(res.data);
- }
- // 重新赋值,改变对象的内存地址,否则添加回复不生效
- this.commentList = commentList;
- this.dialogController?.close();
- this.replyComment = this.firstComment = null;
- this.text = '';
- this.focusableInput = false;
- }).finally(() => {
- this.loading = false;
- });
解决方法2(推荐):
1、把要添加回复的那一条数据解构重新赋值给新的一个对象
2、往新定义的对象里面的列表添加回复数据
3、使用数组splice方法,把原来数组里面的一条数据替换成新定义的对象,
原理:只改变数据中一条数据的内存地址,不改变原来数组的内容地址,性能要高于第一种方案
- // 发送评论
- insertCommentService(commentItem).then((res) => {
- if (this.firstComment) { // 二级评论,相当于回复
- // 必须重新解构,然后再赋值,否则添加回复不生效
- const commentItem = {...this.commentList[this.replyIndex]};
- commentItem.replyList === null && (commentItem.replyList = []);
- commentItem.replyList.push(res.data);// 添加回复列表
- this.commentList.splice(this.replyIndex,1,commentItem);// 替换掉原数据里面的那一条数据
- } else { // 一级评论
- this.commentList.push(res.data);
- }
- // 重新赋值,改变对象的内存地址,否则添加回复不生效
- this.dialogController?.close();
- this.replyComment = this.firstComment = null;
- this.text = '';
- this.focusableInput = false;
- }).finally(() => {
- this.loading = false;
- });
完整代码如下
- import * as colors from '../../theme/color';
- import * as size from '../../theme/size';
- import {getTopCommentListService,insertCommentService} from '../service/Index';
- import { HOST } from '../../config/constant';
- import { CommentInterface } from '../../music/interface/Index';
- import { formatTime } from '../../utils/common';
-
- // 传入buildCommentList方法必须是一个对象形式,否则无法实现响应式
- interface CommentParamsInterface{
- commentList:Array<CommentInterface>
- }
-
- @Component
- export default struct CommentComponent{
- @Prop relationId:number;
- @Prop commentListStr:string;// 评论数组字符串
- @Prop type:string;
- @State commentTotal:number = 0;
- @State commentList:Array<CommentInterface> = [];
- @State text:string = '';// 评论框文字
- @State firstComment:CommentInterface = null;
- @State replyComment:CommentInterface = null;
- @State replyIndex:number = -1;
- @State focusableInput:boolean = false;
- private loading:boolean = false;
- private scroller: Scroller = new Scroller()
- private dialogController:CustomDialogController;
-
- aboutToAppear(){
-
- /**
- * @author: wuwenqiang
- * @description: 获取评论列表
- * @date: 2024-05-25 21:36
- */
- if(this.commentListStr){
- this.commentList = JSON.parse(this.commentListStr) as Array<CommentInterface>;
- }else{
- getTopCommentListService(this.relationId,this.type,1,20).then(res => {
- this.commentList = res.data;
- this.commentTotal = res.total;
- });
- }
- }
-
- /**
- * @author: wuwenqiang
- * @description: 打开评论框弹窗
- * @date: 2024-05-26 14:26
- */
- openDialog():void{
- if(!this.dialogController){
- this.dialogController = new CustomDialogController({
- customStyle: true,
- builder: this.buildCommentInput(),
- alignment: DialogAlignment.Bottom,
- })
- }
- this.dialogController.open()
- }
-
- /**
- * @author: wuwenqiang
- * @description: 创建评论框
- * @date: 2024-05-26 14:26
- */
- @Builder buildCommentInput(){
- Column() {
- Row() {
- TextInput({ text:this.text,placeholder: this.replyComment ? `回复${this.replyComment.username}` : (this.firstComment ? `回复${this.firstComment.username}` : '评论') })
- .layoutWeight(1)
- .focusable(this.focusableInput)
- .height(size.inputHeight)
- .onChange((value) => {
- this.text = value;
- }).onClick(() => {
- this.focusableInput = true
- })
- Button('发送', { type: ButtonType.Capsule, stateEffect: true })
- .backgroundColor(colors.lineBackgroundColor)
- .width(size.btnWidth)
- .enabled(Boolean(this.text))
- .height(size.inputHeight)
- .margin({ left: size.pagePadding })
- .onClick(() => {
- if (this.loading) return;
- this.loading = true;
- const commentItem: CommentInterface = {
- id: 0, //主键
- content: this.text, //评论内容
- parentId: this.replyComment?.id, //父节点id
- topId: this.firstComment?.id, //顶级节点id
- type: this.type, // 类型
- relationId: this.relationId, //影片id
- createTime: "", //创建时间
- updateTime: "", //更新时间
- replyCount: 0, //回复数量
- userId: "", //用户id
- username: "", //用户名
- avater: "", //用户头像
- replyUserId: "", //被回复者id
- replyUserName: "", //被回复者名称
- showCommentCount: "", //显示的回复数量
- replyPageNum: 0,
- replyList: []
- }
- // 发送评论
- insertCommentService(commentItem).then((res) => {
- if (this.firstComment) { // 二级评论,相当于回复
- // 必须重新解构,然后再赋值,否则添加回复不生效
- const commentItem = {...this.commentList[this.replyIndex]};
- commentItem.replyList === null && (commentItem.replyList = []);
- commentItem.replyList.push(res.data);// 添加回复列表
- this.commentList.splice(this.replyIndex,1,commentItem);// 替换掉原数据里面的那一条数据
- } else { // 一级评论
- this.commentList.push(res.data);
- }
- // 重新赋值,改变对象的内存地址,否则添加回复不生效
- this.dialogController?.close();
- this.replyComment = this.firstComment = null;
- this.text = '';
- this.focusableInput = false;
- }).finally(() => {
- this.loading = false;
- });
- })
- }.backgroundColor(colors.blockColor).padding(size.pagePadding)
- }
- .width('100%')
- }
-
- /**
- * @author: wuwenqiang
- * @description: 点击弹出评论框
- * @date: 2024-05-26 14:26
- */
- useReply(item:CommentInterface,index:number){
- if(this.commentListStr){
- this.openDialog();
- }
- this.focusableInput = true;
- this.replyIndex = index;
- if(item.topId){
- this.replyComment = item;// 二级评论,即回复的内容
- this.firstComment = this.commentList.find(aItem => aItem.id === item.topId)
- }else{
- this.replyComment = this.firstComment = item;// 点击的是一级评论
- }
- }
-
- /**
- * @author: wuwenqiang
- * @description: 创建评论列表,参数必须用对象或者接口形式传递,否则参数变化了,视图不更新
- * @date: 2024-05-25 16:30
- */
- @Builder buildCommentList(commentParams:CommentParamsInterface){
- Column({space:size.pagePadding}){
- ForEach(commentParams.commentList,(aItem:CommentInterface,aIndex:number) => {
- Row(){
- Image(aItem.avater ? HOST + aItem.avater : $r('app.media.default_avater'))
- .width(aItem.topId ? size.smallAvaterSize :size.middleAvaterSize)
- .height(aItem.topId ? size.smallAvaterSize :size.middleAvaterSize)
- .borderRadius(aItem.topId ? size.smallAvaterSize :size.middleAvaterSize)
- Column(){
- Text(aItem.topId ? `${aItem.username}▶${aItem.replyUserName}` :aItem.username)
- .fontColor(colors.disableTextColor).margin({bottom:size.miniPadding})
- Text(aItem.content).margin({bottom:size.miniPadding})
- Text(formatTime(aItem.createTime)).fontColor(colors.disableTextColor)
- if(aItem.replyList?.length > 0){
- Blank().height(size.pagePadding)
- // 参数必须用对象或者接口形式传递,否则参数变化了,视图不更新
- this.buildCommentList({commentList:aItem.replyList})
- }
- }.layoutWeight(1)
- .alignItems(HorizontalAlign.Start)
- .margin({left:size.pagePadding})
- .onClick(this.useReply.bind(this,aItem,aIndex))
- }
- .justifyContent(FlexAlign.Start)
- .alignItems(VerticalAlign.Top)
- .width('100%')
- })
- }
- }
-
- build(){
- Column(){
- Text(`${this.commentTotal}条评论`)
- .padding(size.pagePadding)
- .textAlign(TextAlign.Center)
- .border({
- width: { bottom: 1 },
- color: { bottom: colors.borderColor },
- style: { bottom: BorderStyle.Solid }
- }).width('100%')
- Scroll(this.scroller) {
- if(this.commentList.length > 0) {
- // 必须用对象的方式传递,否则this.commentList发生变化之后,视图不会更新
- this.buildCommentList({commentList:this.commentList})
- }else{
- Text('暂无评论')
- .width('100%')
- .height('100%')
- .textAlign(TextAlign.Center)
- .alignSelf(ItemAlign.Center)
- }
- }
- .scrollable(ScrollDirection.Vertical)
- .layoutWeight(1)
- .align(Alignment.Top)
- .padding(size.pagePadding)
- if(!this.commentListStr){
- Divider().height(1).color(colors.borderColor)
- this.buildCommentInput()
- }
- }.width('100%').height('100%')
- }
- }
实现效果如下:
github地址:https://github.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。