vue是一款非常流行的前端框架,它的灵活性和易用性使得它在web开发中有着广泛的应用。知乎是一个非常流行的问答社区,它拥有庞大的用户群体和丰富的内容。在知乎中,回答下的评论功能是非常重要的。在本文中,我们将探讨如何使用vue来实现仿知乎的回答评论功能。
1. 功能简介在知乎中,用户可以在回答下进行评论。评论可以形成一个树状结构,其中每个节点表示一个评论,节点之间有父子关系。用户可以在每个节点下面添加自己的评论,同样会形成树形结构。为了方便用户查看,知乎还会展开和收缩评论。
下面是本文需要实现的功能列表:
用户可以在回答下添加评论;评论可以形成树形结构;用户可以在每个节点下面添加评论;根据层级展示评论;用户可以展开和收缩评论。2. 数据结构设计在实现该功能之前,我们需要先设计数据结构。在知乎中,评论是树形结构,每个节点都有以下属性:
id: 节点的唯一标识符;content: 节点的内容;author: 节点的作者;createtime: 节点创建时间;children: 子节点列表。下面是该数据结构的定义:
interface comment { id: string; content: string; author: string; createtime: number; children?: comment[];}
对于每个回答,我们需要一个评论列表。因为可能有多个回答,我们需要将这些评论列表放到一个对象中,这样就可以通过回答的id来获取对应的评论列表。下面是该数据结构的定义:
interface commentdata { [answerid: string]: comment[];}
3. 实现步骤3.1 显示评论我们需要首先显示评论列表。为了展示树形结构,我们可以使用递归组件。递归组件是指组件可以在自身模板中调用自身。
在vue中,可以使用组件的name属性来实现递归。下面是一个简单的组件:
<template> <div> <div>{{ comment.content }}</div> <div v-if="comment.children"> <comment v-for="c in comment.children" :key="c.id" :comment="c" /> </div> </div></template><script>export default { name: "comment", props: { comment: { type: object, required: true, }, },};</script>
该组件会递归地渲染所有的子节点。
3.2 添加评论在添加评论时,我们需要指定要添加到哪个节点下面。因此,我们需要为每个节点添加一个唯一标识符。在本例中,我们使用uuid来生成唯一标识符。同时,为了方便操作,我们还在每个节点中保存它所属回答的id。
我们可以使用vuex来管理状态。添加评论的流程如下:
用户输入评论内容,并选择要添加到哪个节点下面;触发vuex的action,向服务器发送请求,在服务器中添加评论记录;添加成功后,服务器返回新的评论记录;触发vuex的mutation,将新的评论记录添加到状态中。在组件中,我们可以使用v-model指令来绑定用户输入的评论内容,并使用<select>元素来选择要添加到哪个节点下面。下面是一个组件的例子:
<template> <div> <div> <textarea v-model="content" /> </div> <div> <select v-model="parentid"> <option value="root">回答</option> <option :value="comment.id" v-for="comment in comments" :key="comment.id"> {{ comment.content }} </option> </select> </div> <div> <button @click="addcomment">添加评论</button> </div> </div></template><script>import { mapactions } from "vuex";export default { props: { answerid: { type: string, required: true, }, comment: { type: object, required: false, default: () => null, }, }, data() { return { content: "", parentid: "root", comments: [], }; }, created() { if (this.comment) { this.comments = this.comment.children || []; } else { this.comments = this.$store.state.comments[this.answerid] || []; } }, methods: { ...mapactions("comments", ["addcomment"]), },};</script>
在这个组件中,我们将用户输入的内容和选择的父节点id双向绑定到组件的data中。同时,该组件还接收一个comment属性,如果该属性存在,则表示该组件要添加到一个已有的评论下面;否则,该组件是要添加到回答下面的新评论。
在该组件的created方法中,我们检索该组件要添加的评论的子节点列表。如果当前组件是要添加到一个已有的评论下面,则使用它的子节点列表;否则,我们从vuex的状态中获取所在回答的评论列表。
在组件的addcomment方法中,我们可以调用vuex的action,来向服务器添加新的评论记录:
async addcomment() { const { content, parentid } = this; const answerid = this.answerid; await this.addcomment({ answerid, parentid, content }); this.$emit("added");}
在action处理完毕后,我们触发added事件,以通知父组件刷新界面。
3.3 展开和收缩评论展开和收缩评论是一项比较复杂的功能。需要记录每个节点的展开状态,并能够快速的获取所在节点和它的子节点。我们可以在vuex的状态中记录每个节点的展开状态。
展开和收缩评论的流程如下:
用户点击展开或收缩;触发vuex的mutation,更新对应节点的展开状态;组件根据展开状态,递归地渲染子节点。这个功能我们需要编写一个递归组件。组件会根据节点是否展开来决定是否渲染子节点。在该组件中,我们还需要编写一个展开和收缩按钮。下面是该组件的代码:
<template> <div> <div> <div>{{ comment.content }}</div> <div> <button @click="toggle"> {{ open ? "收起" : "展开" }} </button> </div> </div> <div v-if="open && comment.children"> <comment v-for="subcomment in comment.children" :key="subcomment.id" :comment="subcomment" /> </div> </div></template><script>export default { name: "comment", props: { comment: { type: object, required: true, }, }, computed: { open() { return this.$store.state.expanded[this.comment.id]; }, }, methods: { toggle() { this.$store.commit("toggle", this.comment.id); }, },};</script>
在该组件中,我们使用vuex中的expanded状态来记录每个节点是否展开。在组件的computed中,我们使用该状态来判断当前节点是否展开。在组件的methods中,我们使用vuex的mutation来更新展开状态。
展开状态的处理逻辑很简单,我们只需要在mutation中将对应的节点的展开状态取反即可:
toggle(state, id) { state.expanded[id] = !state.expanded[id];},
4. 总结本文介绍了如何使用vue实现仿知乎的回答评论功能,包括评论的树形结构、添加评论、展开和收缩评论。vue的组件、状态管理和递归组件等特性,为实现该功能提供了非常便利的支持。如果您想尝试实现仿知乎的回答评论功能,本文提供了非常好的参考。
以上就是vue 中如何实现仿知乎的回答评论功能?的详细内容。