Appearance
Comment 评论列表组件 — 基于 list-view 实现的层级评论展示组件,支持递归回复、点赞、用户点击等交互。
t-comment 是一个评论列表组件,内部使用 list-view 渲染,配合 t-comment-item 支持递归嵌套的子评论展示。适用于帖子详情、社交动态、任务评价等需要展示层级评论的场景。
t-comment
list-view
t-comment-item
<template> <view class="p-15"> <t-card class="mb-15" title="Comment 评论组件" sub-title="支持 list-view 顶层滚动、多级回复递归、点赞和回复动作演示。"></t-card> <view class="fv r-16 bg-#fff p-12 mb-15"> <text class="tfs sfwb c-#111827">当前交互</text> <text class="tfs c-#475569 mt-8 slhm-1.6">{{ actionText }}</text> </view> <t-comment :list="commentList" height="620px" :indent="26" :max-depth="5" @reply="handleReply" @like="handleLike" @userclick="handleUserClick"></t-comment> </view> </template> <script setup lang="uts"> const actionText = ref<string>('点击回复、点赞或头像昵称查看交互结果。') function createChildrenList() : UTSJSONObject[] { return [] as UTSJSONObject[] } function createImageList(...items : string[]) : string[] { return items } function createDemoReplies() : UTSJSONObject[] { return [ { id: 'c1-1-1', avatar: '/static/image/avatar/2.jpg', name: '回眸倾城', replyToName: '七七是比熊', content: '多少钱一个', time: '3天前', region: '新疆', likeCount: 1, liked: false, children: createChildrenList() }, { id: 'c1-1-2', avatar: '/static/image/avatar/2.jpg', name: '回眸倾城', replyToName: '七七是比熊', content: '我在乌鲁木齐。', time: '3天前', region: '新疆', likeCount: 1, liked: true, children: createChildrenList() }, { id: 'c1-1-3', avatar: '/static/image/avatar/3.jpg', name: '晚风奶芙', replyToName: '回眸倾城', content: '我也想问下价格。', time: '2天前', region: '苏州', likeCount: 3, liked: false, children: createChildrenList() }, { id: 'c1-1-4', avatar: '/static/image/avatar/1.jpg', name: '青提苏打', replyToName: '七七是比熊', content: '等开售的时候踢我一下。', time: '2天前', region: '南京', likeCount: 2, liked: false, children: createChildrenList() }, { id: 'c1-1-5', avatar: '/static/image/avatar/2.jpg', name: '多云转晴', replyToName: '七七是比熊', content: '视频里真的太可爱了。', time: '1天前', region: '武汉', likeCount: 5, liked: true, images: createImageList('/static/image/D1.jpg', '/static/image/D2.jpg'), children: createChildrenList() }, { id: 'c1-1-6', avatar: '/static/image/avatar/3.jpg', name: '星河入梦', replyToName: '回眸倾城', content: '我也在蹲完整更新。', time: '1天前', region: '成都', likeCount: 1, liked: false, children: createChildrenList() }, { id: 'c1-1-7', avatar: '/static/image/avatar/1.jpg', name: '奶油可可', replyToName: '七七是比熊', content: '有没有喂养清单可以参考?', time: '1天前', region: '杭州', likeCount: 4, liked: false, children: createChildrenList() }, { id: 'c1-1-8', avatar: '/static/image/avatar/2.jpg', name: '晨雾拿铁', replyToName: '七七是比熊', content: '我已经收藏这个帖子了,等后面继续看。', time: '20小时前', region: '宁波', likeCount: 2, liked: false, images: createImageList('/static/image/D2.jpg'), children: createChildrenList() }, { id: 'c1-1-9', avatar: '/static/image/avatar/3.jpg', name: '海盐芝士', replyToName: '回眸倾城', content: '这个楼层已经快变成交流区了,哈哈。', time: '18小时前', region: '青岛', likeCount: 6, liked: true, children: createChildrenList() }, { id: 'c1-1-10', avatar: '/static/image/avatar/1.jpg', name: '晚星汽水', replyToName: '七七是比熊', content: '如果后面有开团通知,也想顺带知道一下。', time: '16小时前', region: '福州', likeCount: 1, liked: false, children: createChildrenList() }, { id: 'c1-1-11', avatar: '/static/image/avatar/2.jpg', name: '山野青柠', replyToName: '七七是比熊', content: '我主要想看后续喂养和日常护理部分。', time: '12小时前', region: '重庆', likeCount: 3, liked: false, children: createChildrenList() }, { id: 'c1-1-12', avatar: '/static/image/avatar/3.jpg', name: '焦糖布丁', replyToName: '回眸倾城', content: '同问价格,也想知道现在有没有排队名单。', time: '8小时前', region: '合肥', likeCount: 2, liked: true, children: createChildrenList() } ] as UTSJSONObject[] } const commentList = ref<UTSJSONObject[]>([ { id: 'c1', avatar: '/static/image/avatar/1.jpg', name: '回眸倾城', content: '可不可以到时候卖一只给我?', time: '3天前', region: '新疆', likeCount: 7, liked: false, images: createImageList('/static/image/D1.jpg', '/static/image/D2.jpg', '/static/image/code.png'), children: [ { id: 'c1-1', name: '七七是比熊', content: '可以,最近会整理一组新照片发出来。', time: '3天前', region: '山东', likeCount: 2, liked: false, isAuthor: true, images: createImageList('/static/image/D2.jpg'), children: createDemoReplies() } ] }, { id: 'c2', avatar: '/static/image/avatar/3.jpg', name: '一只椰子糖', content: '这个配色真的好温柔,已经蹲更新了。', time: '2天前', region: '杭州', likeCount: 12, liked: true, images: createImageList('/static/image/D2.jpg', '/static/image/D1.jpg'), children: [ { id: 'c2-1', name: '七七是比熊', replyToName: '一只椰子糖', content: '下周会发完整视频,记得来看看。', time: '2天前', region: '山东', likeCount: 3, liked: false, isAuthor: true, children: createChildrenList() } ] } ]) function getItemId(item : UTSJSONObject) : string { const id = item.getAny('id') return id == null ? '' : `${id}` } function findCommentById(list : UTSJSONObject[], id : string) : UTSJSONObject | null { for (let i = 0; i < list.length; i++) { const item = list[i] if (getItemId(item) == id) { return item } const children = item.getAny('children') as UTSJSONObject[] | null if (children != null && children.length > 0) { const child = findCommentById(children, id) if (child != null) { return child } } } return null } function handleReply(detail : any) { const payload = detail as UTSJSONObject const item = payload.getAny('item') as UTSJSONObject const name = item.getString('name') ?? '匿名用户' actionText.value = `reply -> ${name}` uni.showToast({ title: `回复 ${name}`, icon: 'none' }) } function handleLike(detail : any) { const payload = detail as UTSJSONObject const item = payload.getAny('item') as UTSJSONObject const id = getItemId(item) if (id == '') { return } const target = findCommentById(commentList.value, id) if (target == null) { return } const likedRaw = target.getAny('liked') const liked = likedRaw == true || `${likedRaw}` == 'true' const likeCountRaw = target.getAny('likeCount') const currentCount = likeCountRaw == null ? 0 : parseInt(`${likeCountRaw}`) const nextCount = liked ? Math.max(0, currentCount - 1) : currentCount + 1 target.set('liked', !liked) target.set('likeCount', nextCount) actionText.value = `${liked ? '取消点赞' : '点赞'} -> ${target.getString('name') ?? '匿名用户'}` } function handleUserClick(detail : any) { const payload = detail as UTSJSONObject const item = payload.getAny('item') as UTSJSONObject const name = item.getString('name') ?? '匿名用户' actionText.value = `userclick -> ${name}` } </script>
{ item, index, replyItem, replyIndex }
{ user, item }
无内置插槽,子项通过 t-comment-item 组件递归渲染。
height
children
maxDepth
replyPageSize
authorBadgeText
t-comment 组件介绍
t-comment是一个评论列表组件,内部使用list-view渲染,配合t-comment-item支持递归嵌套的子评论展示。适用于帖子详情、社交动态、任务评价等需要展示层级评论的场景。t-comment 基础用法
t-comment API
Props
Events
{ item, index, replyItem, replyIndex }{ item, index, replyItem, replyIndex }{ user, item }Slots
无内置插槽,子项通过
t-comment-item组件递归渲染。注意事项
height必须显式设置,list-view 需要明确高度children字段用于递归渲染子评论maxDepth控制递归深度,避免无限嵌套replyPageSize控制子评论按需展开的数量authorBadgeText配置,开启时会在对应评论上显示标识