Впереди мы реализовали функцию комментариев пользователя и отображение комментариев в реальном времени Теперь давайте реализуем функцию ответа пользователя. Эффект от внедрения следующий:
Процесс ответа на комментарии
Разберем процесс ответа на комментарий:
- Пользователь нажимает на комментарий,
inputкоробка получает фокус,inputв штучной упаковкеplaceholderстали回复 @nickname - Пользователь вводит содержимое комментария, затем отправляет его, делая запрос на сервер
- Отображение содержимого комментария пользователя на странице
Внимательные ученики могут обнаружить, что при успешном ответе верхнийxx条评论Никаких обновлений не производилось, потому что я не рассматривал ответы как комментарии при отображении страницы, поэтому число не увеличивалось.
Реализация логики функции ответа
Привязка события объекта комментария
<li
class="comment_li"
v-for="(item,index) in commentList"
:key="item.id"
@click="replyUser(item,index,-1)"
>...</li>
Из приведенного выше кода видно, что мы привязываемreplyUser(item,index,-1)мероприятие. Итак, давайте посмотрим, мы вreplyUserЧто сделано в функции
replyUser(item, index, index2) {
item.index = index; // 为每个评论对象绑定一个index属性,这个index的作用是为了帮助我们能更好的在commmentList中定位到该评论对象
item.index2 = index2; // index2的作用是为了帮助我们区分回复的级别。-1代表回复的是根评论,其他值表示回复的是别人的回复。
this.replyUserComment = item;//replyUserComment的作用是为了保存当前的评论对象,在data中定义
this.commentPlaceholder = `回复 @${item.nickname}:`;//修改placeHolder
this.$refs.content.focus(); //input框获取焦点
},
После описанного выше процесса мы достигли целевого возврата комментария.
Обработка комментариев
<div class="comment_input_box" v-show="commentPop">
<input
:placeholder="commentPlaceholder"
class="comment_input"
v-model="comment_text"
ref="content"
@click="checkComment"
/>
<div class="comment_input_right" @click="checkComment">
<i class="iconfont icon-fasong comment_i" :class="canSend?'comment_i_active':''"></i>
</div>
</div>
здесь дляinputкоробка связываетcheckCommentСобытие, при реализации функции простого комментария, его логика следующая:
checkComment() {
if (this.comment_text == "") {
Toast("评论内容不能为空");
} else {
if (!this.isLogin) {
this.$router.push({
path: "/login"
});
return;
}
let to_user_id = ''; //因为评论是根评论,所以to_user_id和father_comment_id都为空
let father_comment_id = '';
const comment = this.comment_text;
const video_id = this.video_id;
const id = Date.now();
const newComment = {
avatar: this.userInfo.avatar,
comment,
id,
create_time: "刚刚",
nickname: this.userInfo.nickname
};
sendComment({ to_user_id, father_comment_id, comment, video_id }).then(
val => {
this.comment_text = "";
this.hasSend = true;
this.commentList.unshift(newComment);
}
);
}
},
- Поскольку функция комментирования, которую мы реализовали в начале, представляет собой размещенный корневой комментарий, ответить некому, поэтому
to_user_idа такжеfather_comment_idОставляем его пустым. - Теперь, что мы собираемся сделать, это ответить на комментарии пользователей. Нам нужно четко указать, какой пользователь отвечает и на какой комментарий отвечает. Из только что сделанной операции щелчка мы уже можем прояснить эти две части информации. Следовательно, нам нужно изменить приведенную выше логику:
checkComment() {
if (this.comment_text == "") {
Toast("评论内容不能为空");
} else {
if (!this.isLogin) {
this.$router.push({
path: "/login"
});
return;
}
let to_user_id = ''; //因为评论是根评论,所以to_user_id和father_comment_id都为空
let father_comment_id = '';
const comment = this.comment_text;
const video_id = this.video_id;
const id = Date.now();
const newComment = {
avatar: this.userInfo.avatar,
comment,
id,
create_time: "刚刚",
nickname: this.userInfo.nickname
};
----------------------------------------------------
----------------------------------------------------
if(this.replyUserComment){//如果评论对象不为null
to_user_id = this.replyUserComment.from_user_id; // 让回复对象指向评论者
father_comment_id = this.replyUserComment.id //让新评论的father_comment_id指向评论的id
}
-------------------------------------------------------
-------------------------------------------------------
sendComment({ to_user_id, father_comment_id, comment, video_id }).then(
val => {
this.comment_text = "";
this.hasSend = true;
this.commentList.unshift(newComment);
}
);
}
},
Рендеринг содержимого ответа в реальном времени
Реализована возможность сохранять ответы в базу данных. Но опять же, он не отображается на странице в режиме реального времени.
Итак, как и раньше, мы генерируем новый объект комментария и вставляем этот объект в массив. Однако есть логическое различие между вставкой объекта ответа и вставкой корневого комментария.Давайте сначала посмотрим на следующееbilibiliГрафик комментариев:
На ответы также можно отвечать как на комментарии. В проекте мы делим ответы на две категории, одна из которых является первичной, а другая — вторичной.
Для комментариев и ответов обычно используются следующие вложенные форматы данных:
{
avatar:'xxxxxxxxxxxx',
nickname:'xxxxxxxxxxxxx',
comment:'xxxxxxxxxxxxxx',
crete_time:'xxxxxxxxxxxxx',
child_comments:[
{
avatar:'xxxxxxxxxxxx',
nickname:'xxxxxxxxxxxxx',
comment:'xxxxxxxxxxxxxx',
crete_time:'xxxxxxxxxxxxx',
}
......
]
}
- Для ответа нас прямо вставляют в голову.
- Для вторичных ответов мы вставляем непосредственно в хвост.
спереди
replyUserCommentВ функции обратного вызова мы выполнили следующую обработку:
replyUser(item, index, index2) {
item.index = index; // 为每个评论对象绑定一个index属性,这个index的作用是为了帮助我们能更好的在commmentList中定位到该评论对象
item.index2 = index2; // index2的作用是为了帮助我们区分回复的级别。-1代表回复的是根评论,其他值表示回复的是别人的回复。
this.replyUserComment = item;//replyUserComment的作用是为了保存当前的评论对象,在data中定义
this.commentPlaceholder = `回复 @${item.nickname}:`;//修改placeHolder
this.$refs.content.focus(); //input框获取焦点
},
С приведенной выше картинкой мы можем это хорошо понять. Таким образом, мы можем легко написать следующий код для ответа первого уровня:
let index = this.replyUserComment.index;
let index2 = this.replyUserComment.index2;
if (this.replyUserComment.index2 == -1) {
//将一级回复插入到子评论的头部
this.commentList[index].child_comments.unshift(newComment);
} else {
//将二级回复插入到子评论的尾部
this.commentList[index].child_comments.push(newComment)
}
полный код
replyUser(item, index, index2) {
item.index = index;
item.index2 = index2;
this.replyUserComment = item;
this.commentPlaceholder = `回复 @${item.nickname}:`;
this.$refs.content.focus();
},
checkComment() {
if (this.comment_text == "") {
Toast("评论内容不能为空");
} else {
if (!this.isLogin) {
this.$router.push({
path: "/login"
});
return;
}
let father_comment_id = ""; // 默认父评论为null
let to_user_id = "";
let video_id = this.video_id;
let comment = this.comment_text;
const id = Date.now();
const newComment = {
avatar: this.userInfo.avatar,
comment,
id,
create_time: "刚刚",
nickname: this.userInfo.nickname
};
if (this.replyUserComment) {
// 说明不是根评论,而是子评论
father_comment_id = this.replyUserComment.id; // 让father_comment_id 指向这个评论
to_user_id = this.replyUserComment.from_user_id; // 让to_user_id指向父级评论的from_user_id
}
sendComment({ to_user_id, father_comment_id, comment, video_id }).then(
val => {
this.comment_text = "";
this.hasSend = true;
if (!this.replyUserComment) {
this.commentList.unshift(newComment);
} else {
let index = this.replyUserComment.index;
let index2 = this.replyUserComment.index2;
if (this.replyUserComment.index2 == -1) {
//回复一级人
this.commentList[index].child_comments.unshift(newComment);
} else {
//回复二级人
this.commentList[index].child_comments.push(newComment)
}
}
}
);
}
},
На данный момент также реализована функция ответа пользователя.Далее это относительно просто, а остальное похоже на функцию комментариев.
Продолжение следует....