vue + vuex 实现评论和回复

效果图

组件需要的 json 格式

commentList: [  
    {
    id: 1,
    isFirstLevel: 0,
    commentUser: {
        userId: 10086,
        nickName: 'huazizhanye',
        avatar: 'https://huazizhanye.oss-cn-beijing.aliyuncs.com/blogs/images/avatat.jpg'
    },
    content: 'my name is huazizhanye',
    createDate: new Date().toLocaleDateString(),
    childrenList: [
        {
        id: 2,
        isFirstLevel: 1,
        commentUser: {
            userId: 10010,
            nickName: 'mqq',
            avatar: 'https://huazizhanye.oss-cn-beijing.aliyuncs.com/blogs/images/mqq.jpg'
        },
        targetUser: {
            userId: 10086,
            nickName: 'huazizhanye',
            avatar: 'https://huazizhanye.oss-cn-beijing.aliyuncs.com/blogs/images/avatat.jpg'
        },
        content: 'hello huazizhanye',
        createDate: new Date().toLocaleDateString()
        },
        {
        id: 3,
        commentUser: {
            userId: 10086,
            nickName: 'huazizhanye',
            avatar: 'https://huazizhanye.oss-cn-beijing.aliyuncs.com/blogs/images/avatat.jpg'
        },
        targetUser: {
            userId: 10010,
            nickName: 'mqq',
            avatar: 'https://huazizhanye.oss-cn-beijing.aliyuncs.com/blogs/images/mqq.jpg'
        },
        content: 'hello mqq~',
        createDate: new Date().toLocaleDateString(),
        }
    ]
    },
]

参数介绍

评论列表–参数介绍

参数介绍类型
id评论列表id(唯一)Number
userId用户登录后的唯一idNumber
nickName用户名string
avatar用户头像string
userInfo当前用户信息Object
content回复内容string
createDate回复时间Object
commentList评论列表Array
childrenList评论回复列表Array
isFirstLevel一级或二级评论Number
评论列表–childrenList具体参数介绍
参数介绍类型
id评论列表id(唯一)Number
commentUser当前回复的用户Object
targetUser当前将要回复的用户Object
childrenList评论回复列表Array
isFirstLevel一级或二级评论Number
content回复内容string
createDate回复时间Object

组件参数介绍

参数介绍默认
emojiWidth表情框宽560px
showAvatar是否展示头像true
isUseEmoj是否启用表情true
commentNum评论数量0

组件的数据处理

::: note
将数据统一交由vuex处理,如模拟当前已经登录的用户信息等
:::

state: {
    // 评论数量
    commentNum: 0,
    // 当前用户信息
    userInfo:{
      userId: 10086,
      nickName: 'huazizhanye',
      avatar: 'https://huazizhanye.oss-cn-beijing.aliyuncs.com/blogs/images/avatat.jpg'
    }
}

组件的基本使用

// 引用
import Comment from '@/components/Comment'
// 注册
components: {
    Comment
},
// 初始化vuex 中的数据
import {mapState} from 'vuex'
// 在computed中初始化vuex中的数据
computed: {
    ...mapState({
      // 从vuex里面取评论列表
      commentList: state => state.commentList,
      // 从vuex里面当前用户信息
      userInfo: state => state.userInfo,
      // 评论数量
      commentNum: state => state.commentNum
    })
  }
<!-- 在父组件中使用 -->
<comment
    @doSend="doSend($event)"
    @doChidSend="doChidSend(arguments)"
    :commentList="commentList"
    :commentNum="commentNum"
    :avatar="avatar"
    :placeholder="placeholder"
    :isUseEmoj="true"
    ></comment>

新增一级评论

// 父组件方法的调用
methods: {
    doSend(content) {
      console.log('一级评论发送内容' + content)
      let data = {
        // 评论列表的唯一id
        id: this.commentId++,
        // 一级评论
        isFirstLevel: 0,
        content: content,
        createDate: new Date().toLocaleDateString(),
        commentUser: this.userInfo
      }
      this.$store.dispatch('addCommentLevelOne', data)
    }
  }
// store/index.js

state: {
    // 评论数量
    commentNum: 0,
    // 评论列表
    commentList: []
}
actions: {
    // 添加一级评论
    addCommentLevelOne({commit}, data) {
        commit('__addCommentLevelOne', data)
        // 统计评论数量
        commit('__getCommentNum')
    }
},
mutations: {
    // 添加一级评论
    __addCommentLevelOne(state,data) {
        console.log(data)
        state.commentList.unshift(data)
    },
    // 统计评论数量
    __getCommentNum(state) {
        state.commentNum = state.commentList.length
    }
}

回复二级评论

// 父组件方法的调用
methods: {
    doChidSend(e) {
      console.log(e)
      let data = {
        dataList: {
          // id: parseInt(Math.random()*100000000),
          id: this.commentId++,
          // 二级评论
          isFirstLevel: 1,
          // 暂时写死回复评论的人(使用可替换为评论用户)
          commentUser: {
            label: '大佬',
            userId: 10010,
            nickName: 'mqq',
            avatar: 'https://huazizhanye.oss-cn-beijing.aliyuncs.com/blogs/images/mqq.jpg'
          },
          // 回复谁
          targetUser: {
            userId: e[1].userId,
            nickName: e[1].nickName,
            avatar: e[1].avatar,
          },
          content: e[0],
          createDate: new Date().toLocaleDateString()
        },
        // 要回复的id 为了添加评论列表数据
        toCommentId: e[2]
      }
      this.$store.dispatch('addCommentLevelTwo', data)
    }
  }
// store/index.js

state: {
    // 评论数量
    commentNum: 0,
    // 评论列表
    commentList: []
}
actions: {
    // 添加二级评论
    addCommentLevelTwo({commit}, data) {
      commit('__addCommentLevelTwo', data)
    }
},
mutations: {
    // 添加二级评论
    __addCommentLevelTwo(state,data) {
      console.log(state,data)
      if(state.commentList.findIndex(x => x.id === data.toCommentId) !== -1) {
          state.commentList.forEach(items => {
            if(items.id == data.toCommentId) {
              if (items.childrenList) {
                items.childrenList.push(data.dataList)
              } else {
                items.childrenList = []
                items.childrenList.push(data.dataList)
              }
            }
        })
      }
    }
}

至此就结束了,有什么问题,欢迎下方留言~

源码地址

See Github

Vue3中实现评论回复功能,可以采用组件化的方式来设计,通常会涉及到两个主要组件:评论列表评论输入框。这里是一个简化的步骤: 1. **评论列表组件**: - 创建一个`CommentList.vue`文件,展示已有的评论,每个评论都是一个子组件,包含用户头像、昵称、内容时间戳等信息。还可以设置点击展开/收起回复功能。 - 使用`v-for`指令遍历评论数据,并通过事件(如`@click="toggleReply"`)触发显示/隐藏回复区域。 2. **评论输入框组件**: - `CommentInput.vue`负责接收用户输入的内容,一般包括输入框、发送按钮可能的输入验证。 - 提供一个自定义事件,例如`$emit("submitComment", commentContent)`,当用户提交评论时触发这个事件并传递新评论内容。 3. **双向绑定状态管理**: - 使用Vuex或者Reactive API(如Vue 3的refreactive)来管理评论的状态,比如当前选中的评论ID用于展示对应的回复。 4. **父子组件通信**: - 父组件监听评论输入框的事件,然后更新评论数据。如果是在响应式模式下,可以直接操作数据状态变化,使得视图自动更新。 5. **API调用**: - 当用户提交评论时,需要向服务器发送请求,添加新的评论到数据库。可以使用axios或其他HTTP库来处理异步请求。 **示例代码片段**: ```html <!-- CommentList.vue --> <template> <div> <comment v-for="(comment, index) in comments" :key="index" @replyToggle="toggleReply(index)"> </comment> <comment-input :visible="showReplyForm && replyIndex" @submitComment="submitComment" :replyTo="comments[replyIndex]"></comment-input> </div> </template> <script setup> import { ref } from 'vue'; import Comment from './Comment.vue'; import CommentInput from './CommentInput.vue'; const comments = ref([]); let showReplyForm = ref(false); let replyIndex = ref(null); function toggleReply(index) { showReplyForm.value = !showReplyForm.value; replyIndex.value = index; } function submitComment(commentContent) { // 发送请求... } </script> ```
评论 7
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值