Дизайн функции комментариев пользователей [2] (реализация функции ответа)

Vue.js

Впереди мы реализовали функцию комментариев пользователя и отображение комментариев в реальном времени Теперь давайте реализуем функцию ответа пользователя. Эффект от внедрения следующий:

Процесс ответа на комментарии

Разберем процесс ответа на комментарий:

  1. Пользователь нажимает на комментарий,inputкоробка получает фокус,inputв штучной упаковкеplaceholderстали回复 @nickname
  2. Пользователь вводит содержимое комментария, затем отправляет его, делая запрос на сервер
  3. Отображение содержимого комментария пользователя на странице

Внимательные ученики могут обнаружить, что при успешном ответе верхний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':''">&#xe608;</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);
          }
        );
      }
    },
  1. Поскольку функция комментирования, которую мы реализовали в начале, представляет собой размещенный корневой комментарий, ответить некому, поэтомуto_user_idа такжеfather_comment_idОставляем его пустым.
  2. Теперь, что мы собираемся сделать, это ответить на комментарии пользователей. Нам нужно четко указать, какой пользователь отвечает и на какой комментарий отвечает. Из только что сделанной операции щелчка мы уже можем прояснить эти две части информации. Следовательно, нам нужно изменить приведенную выше логику:
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)
              }
            }
          }
        );
      }
    },

На данный момент также реализована функция ответа пользователя.Далее это относительно просто, а остальное похоже на функцию комментариев.

Продолжение следует....