Vuejsuniapp开发评论模块递归渲染回复评论

6次阅读

共计 3004 个字符,预计需要花费 8 分钟才能阅读完成。

先看需求

::: hljs-center

:::

我们需要将评论数据进行渲染成如图所示,后端给我们返回的数据格式又是啥样的呢?答案就是一级一级的父子层级嵌套的数据结构:
::: hljs-center

:::
面对这样的数据结构,我们怎么渲染呢?
通过递归的形式渲染就比较可行

首先,我们创建一个回复评论的组件,父组件中将评论的回复数组传给子组件,在子组件中进行渲染,如果回复的数组中还有子回复那么这时候把数据传给回复组件即可。这样就能达到递归渲染数组的目的了。

引用回复组件

在父组件中引用回复组件

import replyComment from '../comment-item/comment-item.vue'

components: {replyComment},

<!-- 回复 -->
                                    <replyComment style="padding-left: 68rpx;" :commentChildren="item.children" @child_up="handleCommentUp"
                                     @child_down="handleCommentDown" @child_reply="handleCommentInputPopupShow"></replyComment>

回复组件

replyComment:

<template>
    <view class="reply-content-wrapper">
        <view class="comment-reply-data" v-for="(item,index) in commentChildren" :key="index">
            <view class="comment-reply-user">
                <view class="comment-root-header flex-row">
                    <image :src="item.criticImg" mode=""></image>
                    <view class="username">
                        {{item.criticName}}
                    </view>
                </view>
                <view class="replycomment-content">
                    <text> 回复 </text><text class="replyer">{{item.reCriticName}}</text>
                    <text>{{item.comment}}</text>
                </view>
                <view class="comment-data flex-row-space">
                    <view class="create-time">
                        {{formatDate(item.createTime)}}
                    </view>
                    <view class="operation-icon flex-row">
                        <view class="operation-item">
                            <i class="icon iconzan_before" @tap="handleCommentUp(item.id)"></i>
                            <text>{{item.supportCount}}</text>
                        </view>
                        <view class="operation-item">
                            <i class="icon iconcai_before" @tap="handleCommentDown(item.id)"></i>
                            <text>{{item.opposeCount}}</text>
                        </view>
                        <view class="operation-item">
                            <i class="icon iconpinglun" @tap="handleCommentInputPopupShow(item)"></i>
                        </view>
                    </view>
                </view>
            </view>
            <replyComment v-if="item.children" :commentChildren="item.children" @child_up="handleCommentUp" @child_down="handleCommentDown"
             @child_reply="handleCommentInputPopupShow"></replyComment>
        </view>
    </view>
</template>

<script>
    import {formateTime} from '../../utils/index.js'
    export default {
        name: 'replyComment',
        props: {
            commentChildren: {
                type: Array,
                default: []}
        },
        data() {return {};
        },
        methods: {
            // 格式化时间
            formatDate(time) {if (!time) {return ''}
                return formateTime(time)
            },
            handleCommentUp(id) {this.$emit('child_up', id)
            },
            handleCommentDown(id) {this.$emit('child_down', id)
            },
            handleCommentInputPopupShow(item) {this.$emit('child_reply', item)
            },
        }
    }
</script>

<style lang="less" scoped>
    .comment-reply-data {
        .comment-root-header {
            color: #333333;
            margin: 27rpx 0;

            image {
                width: 48rpx;
                height: 48rpx;
                border-radius: 40rpx;
                margin-right: 20rpx;
            }
        }

        .comment-root-user {border-bottom: 2rpx solid #eee;}

        image {
            width: 48rpx;
            height: 48rpx;
            border-radius: 40rpx;
            margin-right: 20rpx;
        }

        .replycomment-content {
            margin-bottom: 20rpx;
            word-break: break-all;

            .replyer {
                display: inline-block;
                padding: 0 12rpx;
                color: #333333;
                position: relative;
                bottom: 2rpx;
            }
        }

        .comment-data {
            color: #666;
            line-height: 20rpx;
            font-size: 20rpx;
            padding-bottom: 28rpx;
            border-bottom: 2rpx solid #EDEDED;

            .operation-icon {
                .operation-item {
                    margin-left: 49rpx;

                    .icon {font-size: 22rpx;}
                }
            }

            // 点赞
            .active-support {
                animation-name: support;
                animation-duration: 500ms;
                animation-iteration-count: 1;
                animation-fill-mode: forwards;
            }
        }
    }
</style>

那么实际效果呢?

::: hljs-center

:::

其实,刚开始看到这个数据结构十分头疼,后来仔细想想递归是能够解决的,然后就开始动手,没想到真就实现了。开发中我们可能会遇到各种需求,只要冷静下来好好想想,总能找到解决办法的。

老铁们可以关注我的个人公众号

也可以去我的博客瞅瞅

正文完
 0