ホームページ > 記事 > ウェブフロントエンド > Zhihu のような回答とコメント機能を Vue に実装するにはどうすればよいですか?
Vue は非常に人気のあるフロントエンド フレームワークであり、その柔軟性と使いやすさにより、Web 開発で広く使用されています。 Zhihu は、大規模なユーザー ベースと豊富なコンテンツを備えた非常に人気のある Q&A コミュニティです。 Zhihuでは、回答の下にあるコメント機能が非常に重要です。この記事では、Vue を使用して Zhihu のような回答およびコメント機能を実装する方法を検討します。
Zhihu では、ユーザーは回答の下にコメントを付けることができます。コメントはツリー構造を形成できます。各ノードはコメントを表し、ノード間には親子関係があります。ユーザーは各ノードの下に独自のコメントを追加でき、ツリー構造も形成されます。ユーザーが閲覧しやすいように、Zhihu はコメントを拡大および縮小することもできます。
次は、この記事で実装する必要がある機能のリストです:
この機能を実装する前に、まずデータ構造を設計する必要があります。 Zhihu では、コメントはツリー構造になっており、各ノードには次の属性があります:
データ構造の定義は次のとおりです:
interface Comment { id: string; content: string; author: string; createTime: number; children?: Comment[]; }
各回答には、コメントのリストが必要です。複数の回答がある可能性があるため、回答の ID によって対応するコメント リストを取得できるように、これらのコメント リストをオブジェクトに入れる必要があります。データ構造の定義は次のとおりです:
interface CommentData { [answerId: string]: Comment[]; }
最初にコメント リストを表示する必要があります。ツリー構造を表示するには、再帰コンポーネントを使用できます。再帰コンポーネントとは、コンポーネントが独自のテンプレート内でそれ自体を呼び出すことができることを意味します。
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>
このコンポーネントはすべての子ノードを再帰的にレンダリングします。
コメントを追加するときは、コメントを追加するノードを指定する必要があります。したがって、各ノードに一意の識別子を追加する必要があります。この例では、UUID を使用して一意の識別子を生成します。同時に、操作の便宜のために、それが属する回答の ID も各ノードに保存します。
Vuex を使用して状態を管理できます。コメントを追加するプロセスは次のとおりです:
コンポーネントでは、v-model ディレクティブを使用してユーザーが入力したコメントの内容をバインドし、221f08282418e2996498697df914ce4e
要素を使用してどのノードを選択するかを選択できます。に追加してください。以下はコンポーネントの例です。
<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 をコンポーネントのデータに双方向にバインドします。同時に、コンポーネントは comment
属性も受け取ります。この属性が存在する場合、コンポーネントが既存のコメントに追加されることを意味し、そうでない場合、コンポーネントは新しいコメントに追加されることを意味します答えの下にあります。
コンポーネントの created
メソッドでは、コンポーネントによって追加されるコメントの子ノードのリストを取得します。現在のコンポーネントを既存のコメントに追加する場合は、その子ノード リストを使用します。それ以外の場合は、Vuex 状態から回答のコメント リストを取得します。
コンポーネントの addComment
メソッドでは、Vuex のアクションを呼び出して、新しいコメント レコードをサーバーに追加できます。
async addComment() { const { content, parentId } = this; const answerId = this.answerId; await this.addComment({ answerId, parentId, content }); this.$emit("added"); }
アクションが処理された後、## をトリガーします。 #added イベントは、親コンポーネントにインターフェースを更新するよう通知します。
<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 状態を使用して、各ノードが展開されているかどうかを記録します。計算コンポーネントでは、この状態を使用して現在のノードが展開されているかどうかを判断します。コンポーネントのメソッドでは、Vuex の Mutation を使用して展開された状態を更新します。
で対応するノードの展開状態を反転するだけです。
toggle(state, id) { state.expanded[id] = !state.expanded[id]; },
本文介绍了如何使用Vue实现仿知乎的回答评论功能,包括评论的树形结构、添加评论、展开和收缩评论。Vue的组件、状态管理和递归组件等特性,为实现该功能提供了非常便利的支持。如果您想尝试实现仿知乎的回答评论功能,本文提供了非常好的参考。
以上がZhihu のような回答とコメント機能を Vue に実装するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。